.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/
posted @ 2020-04-07 09:40  Alex_Mercer  阅读(2002)  评论(0编辑  收藏  举报