.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/