zoukankan      html  css  js  c++  java
  • .NetCore IdentityServer4与EF实体结合

    参考链接

    运行环境:
    .Net Core 3.0
    ef 3.0

    1.安装Identity,简单的开启控制权限

    Nuget包

    目录说明

    2.根据现有的数据库生成 实体类

    参考链接:https://www.cnblogs.com/luckypc/p/10937598.html

    如何在vs中打开 Nuget包管理器
    工具-Nuget包管理器-程序包管理器控制台

    生成代码

    Scaffold-DbContext "Data Source=.;Initial Catalog=OA;User ID=sa;Password=123456" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Force
    

    3.将Identity 与 EF 绑定结合

    IdentityServerConfig 代码

    public class IdentityServerConfig
        {
            //添加Config.cs配置IdentityResource
            public static IEnumerable<IdentityResource> GetIdentityResourceResources()
            {
                return new List<IdentityResource>
                {
                    new IdentityResources.OpenId(), //必须要添加,否则报无效的scope错误
                    new IdentityResources.Profile()
                };
            }
    
    
    
            /// <summary>
            /// 添加api资源
            /// </summary>
            /// <returns></returns>
            public static IEnumerable<ApiResource> GetResources()
            {
                return new List<ApiResource>
                {
    
                    new ApiResource("api1","My Api",new List<string>(){ "userName", "userCode"})
                };
            }
            /// <summary>
            /// 添加客户端,定义一个可以访问此api的客户端
            /// </summary>
            /// <returns></returns>
            public static IEnumerable<Client> GetClients()
            {
                return new List<Client>
                    {
                        new Client
                        {
                            ClientId = "client",
                           //需要账户密码模式
                            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                           
                            // 用于认证的密码
                            ClientSecrets =
                            {
                                new Secret("1234554".Sha256())
                            },
                               AllowedScopes = { "api1",IdentityServerConstants.StandardScopes.OpenId, //必须要添加,否则报forbidden错误
                      IdentityServerConstants.StandardScopes.Profile }
                        }
    
                    };
    
            }
        }
    

    CustomResourceOwnerPasswordValidator 自定义验证器,实现IResourceOwnerPasswordValidator接口

    	/// <summary>
    	/// 自定义 Resource owner password 验证器
    	/// </summary>
    	public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    	{
    
    		private readonly OAContext dbContext=new OAContext();//EF上下文
    
    		/// <summary>
    		/// 验证
    		/// </summary>
    		/// <param name="context"></param>
    		/// <returns></returns>
    		public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    		{
    			BaseUser user = dbContext.BaseUser.FirstOrDefault(a => a.Code.Equals(context.UserName) && a.Password.Equals(context.Password));
    			//此处使用context.UserName, context.Password 用户名和密码来与数据库的数据做校验
    			if (user!=null)
    			{
    			
    
    				//验证通过返回结果 
    				//subjectId 为用户唯一标识 一般为用户id
    				//authenticationMethod 描述自定义授权类型的认证方法 
    				//authTime 授权时间
    				//claims 需要返回的用户身份信息单元 此处应该根据我们从数据库读取到的用户信息 添加Claims 如果是从数据库中读取角色信息,那么我们应该在此处添加
    				context.Result = new GrantValidationResult(
    					user.Id.ToString(),
    					OidcConstants.AuthenticationMethods.Password, DateTime.Now,
    					user.Claims);
    			}
    			else
    			{
    				//验证失败
    				context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
    			}
    			return Task.CompletedTask;
    		}
    	}
    

    CustomProfileService 实现IProfileService接口

    	//IdentityServer提供了接口访问用户信息,但是默认返回的数据只有sub,就是上面设置的subject: context.UserName,要返回更多的信息,需要实现IProfileService接口
    	public class CustomProfileService : IProfileService
    	{
    		private readonly OAContext dbContext = new OAContext();//EF上下文
    		/// <summary>
    		/// 只要有关用户的身份信息单元被请求(例如在令牌创建期间或通过用户信息终点),就会调用此方法
    		/// </summary>
    		/// <param name="context">The context.</param>
    		/// <returns></returns>
    		public virtual Task GetProfileDataAsync(ProfileDataRequestContext context)
    		{
    			//2020.04.14 不考虑验证
    
    			//context.Subject.Claims就是之前实现IResourceOwnerPasswordValidator接口时claims: user.Claims给到的数据。
    			//另外,经过调试发现,显示执行ResourceOwnerPasswordValidator 里的ValidateAsync,然后执行ProfileService 里的IsActiveAsync,GetProfileDataAsync。
    			var claims = context.Subject.Claims.ToList();
    			//set issued claims to return
    			context.IssuedClaims = claims.ToList();
    
    			return Task.CompletedTask;
    		}
    
    		/// <summary>
    		/// 验证用户是否有效 例如:token创建或者验证
    		/// </summary>
    		/// <param name="context">The context.</param>
    		/// <returns></returns>
    		public virtual Task IsActiveAsync(IsActiveContext context)
    		{
    			//2020.04.14 不考虑验证
    			//Logger.LogDebug("IsActive called from: {caller}", context.Caller);
    			//string userID = context.Subject.GetSubjectId();
    			
    			//var user = dbContext.BaseUser.FirstOrDefault(a => a.Id.Equals(Convert.ToInt32(userID)));
    			//context.IsActive = user?.Effective == true;
    			context.IsActive =  true;
    			return Task.CompletedTask;
    		}
    	}
    

    Startup 配置

    public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
    
    
                services.AddIdentityServer()
                .AddInMemoryApiResources(IdentityServerConfig.GetResources())//添加配置的api资源
                  .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResourceResources()) //.自定义身份资源资源 ,暂时没有啥效果
                .AddInMemoryClients(IdentityServerConfig.GetClients())//添加客户端,定义一个可以访问此api的客户端
                   .AddProfileService<CustomProfileService>()// 添加自定义 claim
                 .AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>()//过滤器验证用户
                .AddDeveloperSigningCredential();
    
    
                services.AddAuthentication("Bearer")
                   .AddIdentityServerAuthentication(options =>
                   {
                       options.Authority = "http://localhost:5000";
                       options.RequireHttpsMetadata = false;
                       options.ApiName = "api1";
                   });
            }
    
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseIdentityServer();
                app.UseAuthentication();//开启权限认证
    
                app.UseRouting();
    
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
    

    TestController 测试使用的控制器

    在控制器中,可以用这个得到context.FirstOrDefault(a=>a.Type=="userName").Value 对应的自定义信息

      [Route("test/[action]")]
        [ApiController]
       
        public class TestController : ControllerBase
        {
            // GET: api/Test
            [HttpGet]
            [Authorize]
            public IActionResult Get()
            {
                IEnumerable<System.Security.Claims.Claim> context = HttpContext.User.Claims;
                return new JsonResult(from c in HttpContext.User.Claims select new { c.Type, c.Value });
            }
            [HttpGet]
            public IEnumerable<string> Get2()
            {
                return new string[] { "阿萨德", "value啊啊2" };
            }
    
         
            // POST: api/Test
            [HttpPost]
            public void Post([FromBody] string value)
            {
            }
    
        }
    

    调用这个接口,可以得到自定义返回的值 http://localhost:5000/connect/userinfo
    参考链接:https://www.cnblogs.com/jaycewu/p/7791102.html todo,这个还可以再看看权限认证的过滤器如何使用

    PostMan测试说明

    请求Token

    post地址:http://localhost:5000/connect/token
    form-data参数:
        client_id    client
        client_secret    1234554
        grant_type    password
        username    你的用户名
        password    你的密码
    

    访问API控制器,需要带上token,否则401报错,没有权限

    http://localhost:5000/test/get
    

    根据Token获取用户信息

    http://localhost:5000/connect/userinfo
    
  • 相关阅读:
    Date类型转换成LocalDateTime 类型
    连接mysql数据库执行写入语句
    排序的的值为非数字时的处理方法
    git所遇到的问题
    visual studio快捷键
    Win10编译chromium
    下载chromium CIPD client失败的解决办法
    Linux内核源代码情景分析
    【赵强老师】史上最详细的PostgreSQL体系架构介绍
    3.Consul 安装配置(Proxysql+mgr)
  • 原文地址:https://www.cnblogs.com/Alex-Mercer/p/12698025.html
Copyright © 2011-2022 走看看