zoukankan      html  css  js  c++  java
  • .Net Core 使用identity实现Token登录功能

    参考链接

    todo,需要完成的实体去完善这个文档
    如何根据现有的数据库以及实体区配置呢

    • 我们需要接入已有用户体系,只需实现IProfileService和IResourceOwnerPasswordValidator接口即可,并且在Startup配置Service时不再需要AddTestUsers,因为将使用我们自己的用户信息。

    我这边逐步说明需要配置的哪些玩意

    1.IResourceOwnerPasswordValidator 接口

    在demo示例里面,我将临时用户的更改为数据库查询接口,这个最好后期改成实体,有注入风险

    	/// <summary>
    		/// 验证
    		/// </summary>
    		/// <param name="context"></param>
    		/// <returns></returns>
    		public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    		{
                //此处使用context.UserName, context.Password 用户名和密码来与数据库的数据做校验
                //if (_users.ValidateCredentials(context.UserName, context.Password))
                if (LoginCheck(context.UserName, context.Password)) //临时测试
                {
    
    				var user = _users.FindByUsername(context.UserName);
    
                    //验证通过返回结果 
                    //subjectId 为用户唯一标识 一般为用户id
                    //authenticationMethod 描述自定义授权类型的认证方法 
                    //authTime 授权时间
                    //claims 需要返回的用户身份信息单元 此处应该根据我们从数据库读取到的用户信息 添加Claims 如果是从数据库中读取角色信息,那么我们应该在此处添加
    
                    string str = @"select Password,* from Base_User 
    where code='" + context.UserName + "'";
                    DataTable dt = new DataTable();
                    dt = RunSql(str);
                    
                    //自定义了一个地址,需要在config设置才可以得到
                    var Claims = new List<Claim>() { new Claim("自定义信息", dt.Rows[0]["Name"].ToString()) };
                    context.Result = new GrantValidationResult(
                        dt.Rows[0]["ID"].ToString(),
                        OidcConstants.AuthenticationMethods.Password, _clock.UtcNow.UtcDateTime,
                        Claims);
    
                    //context.Result = new GrantValidationResult(
                    //    user.SubjectId ?? throw new ArgumentException("Subject ID not set", nameof(user.SubjectId)),
                    //    OidcConstants.AuthenticationMethods.Password, _clock.UtcNow.UtcDateTime,
                    //    user.Claims);
                }
    			else
    			{
    				//验证失败
    				context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
    			}
    			return Task.CompletedTask;
    		}
    
            /// <summary>
            /// 这边只是简单的测试使用数据库
            /// </summary>
            /// <param name="code"></param>
            /// <param name="pwd"></param>
            /// <returns></returns>
            public static bool LoginCheck(string code,string pwd)
            {
                string str = @"select Password,* from Base_User 
    where code='"+code+"'";
                DataTable dt = new DataTable();
                dt = RunSql(str);
                if (dt.Rows.Count > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            public static DataTable RunSql(string sqlStr)
            {
                using (SqlConnection sqlConnection1 = new SqlConnection("Data Source=ALEX;Initial Catalog=RiBaoOA;User ID=sa;Password=123456;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"))
                {
                    using (SqlDataAdapter sqlDataAdapter1 = new SqlDataAdapter(sqlStr, sqlConnection1))
                    {
                        DataTable DT = new DataTable();
                        sqlDataAdapter1.Fill(DT);
                        return DT;
                    }
                }
    
            }
    
    

    2.IProfileService

    在这个里面,我重新赋值 Claims,主要就是为了测试自定义声明

    public class CustomProfileService: IProfileService
    	{
    		/// <summary>
    		/// The logger
    		/// </summary>
    		protected readonly ILogger Logger;
    
    		/// <summary>
    		/// The users
    		/// </summary>
    		protected readonly TestUserStore Users;
    
    		/// <summary>
    		/// Initializes a new instance of the <see cref="TestUserProfileService"/> class.
    		/// </summary>
    		/// <param name="users">The users.</param>
    		/// <param name="logger">The logger.</param>
    		public CustomProfileService(TestUserStore users, ILogger<TestUserProfileService> logger)
    		{
    			Users = users;
    			Logger = logger;
    		}
    
    		/// <summary>
    		/// 只要有关用户的身份信息单元被请求(例如在令牌创建期间或通过用户信息终点),就会调用此方法
    		/// </summary>
    		/// <param name="context">The context.</param>
    		/// <returns></returns>
    		public virtual Task GetProfileDataAsync(ProfileDataRequestContext context)
    		{
    			context.LogProfileRequest(Logger);
    
    			//判断是否有请求Claim信息
    			if (context.RequestedClaimTypes.Any())
    			{
                    ////根据用户唯一标识查找用户信息
                    //var user = Users.FindBySubjectId(context.Subject.GetSubjectId());
                    //if (user != null)
                    //{
                    //	//调用此方法以后内部会进行过滤,只将用户请求的Claim加入到 context.IssuedClaims 集合中 这样我们的请求方便能正常获取到所需Claim
    
                    //	context.AddRequestedClaims(user.Claims);
                    //}
                    var Claims = new List<Claim>() { new Claim("自定义信息", "名称") };
                    context.AddRequestedClaims(Claims);
                }
    
    			context.LogIssuedClaims(Logger);
    
    			return Task.CompletedTask;
    		}
    
    		/// <summary>
    		/// 验证用户是否有效 例如:token创建或者验证
    		/// </summary>
    		/// <param name="context">The context.</param>
    		/// <returns></returns>
    		public virtual Task IsActiveAsync(IsActiveContext context)
    		{
    			Logger.LogDebug("IsActive called from: {caller}", context.Caller);
    
    			var user = Users.FindBySubjectId(context.Subject.GetSubjectId());
    			//context.IsActive = user?.IsActive == true;
                context.IsActive = true;
                return Task.CompletedTask;
    		}
    	}
    

    3.Identity4中需要在 配置文件中增加claim

    public static IEnumerable<ApiResource> GetApiResources()
            {
                return new List<ApiResource>
                {
    //                new ApiResource("api1", "My API")
                    new ApiResource("api1", "My API",new List<string>(){"自定义信息"})
                };
            }
    

    4.带上token请求API接口,通过HttpContext.User.Claims 可以得到你想要的数据

    其中 sub 就是用户的唯一标识,这个可以看着后期如何优化。

    5.postman测试

    请求token

    post地址:http://localhost:46270/connect/token
    参数:
    grant_type  password
    client_id   ro.client
    client_secret   secret
    username    用户名
    password    密码
    scope   api1
    
    返回如下:
    {
        "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjAxOGZlZmIyYmVmN2IxNTY2NzhmMDZkYTRiNGY4NTgzIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1ODY2ODQ0ODksImV4cCI6MTU4NjY4ODA4OSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo0NjI3MCIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjQ2MjcwL3Jlc291cmNlcyIsImFwaTEiXSwiY2xpZW50X2lkIjoicm8uY2xpZW50Iiwic3ViIjoiODQiLCJhdXRoX3RpbWUiOjE1ODY2ODQ0ODcsImlkcCI6ImxvY2FsIiwi6Ieq5a6a5LmJ5L-h5oGvIjoi5ZCN56ewIiwic2NvcGUiOlsiYXBpMSJdLCJhbXIiOlsicHdkIl19.2_O07JwtOpD2cq8PFxu9tBU6rpSOw_XI0LrfF7QYivNylyeeb7kvNsEElzVtW2ulx6kjLCDF6tgskrjkFp3JhZ8H3hPiJXDxlwJ-an7D2k5lw1Bcool7WiD9q8IkobEFx-Zg6PAUocr-BCr9yEldkA41pPLtfuf3oZwkS2333AcYnixRNJbX3hHVA21cXSMuj-5rDp899uNeOUrvhrAqSD_eS-dQrdCfa00EwSfDyd6ruFnH3IT0AD0TvBDHjzYyl7VNdUpX1yHnjSKr60oahVtuMi_sy8HGFIgsn1_kKNaYayaiFGsiI7cG_L7FJZ2AksNVW4r1_cEyP1xNaxD-Ag",
        "expires_in": 3600,
        "token_type": "Bearer"
    }
    
    

    带上token请求解析。这个暂时没看懂

    post地址:http://localhost:46270/connect/userinfo
    

    带上token请求api.

    http://localhost:46269/identity/
    
  • 相关阅读:
    Java并发编程:同步容器
    poj 1961 Period
    html与JacaScript中的重要思想:预留后路、向后兼容、js分离
    SQL从头開始
    android帧动画,移动位置,缩放,改变透明度等动画解说
    COCOS学习笔记--Cocod2dx内存管理(三)-Coco2d-x内存执行原理
    构建基于Javascript的移动CMS——生成博客(二).路由
    Oracle 单表选择率
    刚接触Joomla,写一下瞎折腾的初感受~
    Android学习笔记之ProgressBar案例分析
  • 原文地址:https://www.cnblogs.com/Alex-Mercer/p/12651519.html
Copyright © 2011-2022 走看看