1. 業務場景 IdentityServer4 授權配置 中的 ,設置的是具體的 API 站點名字,也就是使用方設置的 ,示例代碼: 上面兩個 配置要一致,問題來了,因為授權中心的 配置是整個 API 服務,如果我們存在多個 配置,比如一個前臺和後臺,然後都需要訪問 ,就會出現一些問題。 比如, 服 ...
1. 業務場景
IdentityServer4 授權配置Client
中的AllowedScopes
,設置的是具體的 API 站點名字,也就是使用方設置的ApiName
,示例代碼:
//授權中心配置
new Client
{
ClientId = "client_id_1",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowOfflineAccess = true,
AccessTokenLifetime = 3600 * 6, //6小時
SlidingRefreshTokenLifetime = 1296000, //15天
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes =
{
"api_name1"
},
}
//API 服務配置
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = $"http://localhost:5000",
ApiName = "api_name1",
RequireHttpsMetadata = false
});
上面兩個api_name1
配置要一致,問題來了,因為授權中心的scope
配置是整個 API 服務,如果我們存在多個Client
配置,比如一個前臺和後臺,然後都需要訪問api_name1
,就會出現一些問題。
比如,api_name1
服務中的一個介面服務配置代碼:
[Authorize()]
[Route("api/values")]
[HttpGet]
public IActionResult Get()
{
return Ok();
}
Authorize()
的配置,說明api/values
介面需要授權後訪問,如果授權中心配置了兩個Client
(前臺和後臺),並且scope
都包含了api_name1
,現在就會出現兩種情況:
- 前臺
Client
和後臺Client
,都需要授權後訪問api/values
介面:沒有問題。 - 前臺
Client
不需要授權後訪問,後臺Client
需要授權後訪問:有問題,前臺Client
沒辦法訪問了,因為api/values
介面設置了Authorize()
。
其實,說明白些,就是該如何讓 API 服務指定Client
授權訪問?比如:[Authorize(ClientId = 'client_id_1')]
。
2. 解決方案
沒有[Authorize(ClientId = 'client_id_1')]
這種解決方式,不過可以使用[Authorize(Roles = 'admin')]
。
授權中心的ResourceOwnerPasswordValidator
代碼,修改如下:
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private readonly IUserService _userService;
public ResourceOwnerPasswordValidator(IUserService userService)
{
_userService = userService;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var user = await _userService.Login(context.UserName, context.Password);
if (user != null)
{
var claims = new List<Claim>() { new Claim("role", "admin") }; //根據 user 對象,設置不同的 role
context.Result = new GrantValidationResult(user.UserId.ToString(), OidcConstants.AuthenticationMethods.Password, claims);
}
}
}
授權中心的startup
配置,修改如下
var builder = services.AddIdentityServer();
builder.AddTemporarySigningCredential()
//.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(new List<ApiResource>
{
new ApiResource("api_name1", "api1"){ UserClaims = new List<string> {"role"}}, //增加 role claim
new ApiResource("api_name2", "api2"){ UserClaims = new List<string> {"role"}}
})
.AddInMemoryClients(Config.GetClients());
API 服務介面,只需要配置如下:
[Authorize()]
[Route("api/values")]
[HttpGet]
public IActionResult Get()
{
return Ok();
}
[Authorize(Roles = "admin")]
[Route("api/values2")]
[HttpGet]
public IActionResult Get2()
{
return Ok();
}
[Authorize(Roles = "admin,normal")]
[Route("api/values3")]
[HttpGet]
public IActionResult Get3()
{
return Ok();
}
需要註意的是,api/values
介面雖然沒有設置具體的Roles
,但每個Role
都可以訪問。