參考鏈接
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/