IdentityServer4 QuckStart Authorization and Custom Claims Problems

  • 2021-11-14 05:18:00
  • OfStack

Recently, I have been tossing IdentityServer4. For simplicity, I directly used the official QuickStart sample project as the foundation to build it. There is 1 for 1. To protect an API, it feels like it takes more time than writing an API.

This article is based on ASP. NET CORE 3.1, IdentityServer 4 3.1. 3. Codes are all key codes, which are posted too much.

I finally ran, and the final task should be implemented to the authorized work. Used in API Authorize Used to restrict user access.


[Route("api/[controller]")]
[Authorize(Roles = "Administrator")]
[ApiController]
public class UserInfoController : ControllerBase
{
 /// <summary>
 ///  No parametric GET Request 
 /// </summary>
 /// <returns></returns>
 [HttpGet()]
 [ProducesResponseType(typeof(ReturnData<IEnumerable<UserInfo>>), Status200OK)]
 public async Task<ActionResult> Get()
 {
 var info = new Info<UserInfo>();
 return Ok(new ReturnData<IEnumerable<UserInfo>>(await info.Get()));
 }

However, in use, although the right to obtain authorization, but can not normally access API, 1 straight prompt 401 no authorization error. After careful examination, it is found that the content returned by IdentityServer4 does not return the content of role JwtClaimTypes , without it, Authorize Doesn't work properly.


{
 "nbf": 1587301921,
 "exp": 1587305521,
 "iss": "http://localhost:5000",
 "aud": "MonitoringSystemApi",
 "client_id": "webClient",
 "sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
 "auth_time": 1587301921,
 "idp": "local",
 "scope": [
 "roles",
 "MonitoringSystemApi",
 "offline_access"
 ],
 "amr": [
 "pwd"
 ]
}

Realization

Looking at Config. cs, IdentityServer4 returns only two types of IdentityResource by default: openid and profile. According to the official statement, the content defined by this thing will be returned to the user's token. Reference. Then arrange it decisively.


public static IEnumerable<IdentityResource> Ids =>
new List<IdentityResource>
{
 new IdentityResources.OpenId(),
 new IdentityResources.Profile(),
 new IdentityResource ("roles", new List<string> { JwtClaimTypes.Role }){ Required = true}
};

public static IEnumerable<Client> Clients =>
 new List<Client>
 {
 new Client
 {
  ClientId = "webClient",
  ClientSecrets = { new Secret("secret".Sha256()) },
  AllowOfflineAccess = true,
  AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
  // scopes that client has access to
  AllowedScopes = {
  "roles",

  "MonitoringSystemApi" }
 },

Before executing, you need to ensure that the user data in the database already contains Claim of role.


// Add user code 
bob = new ApplicationUser
{
 UserName = "bob"
};
var result = userMgr.CreateAsync(bob, "Pass123$").Result;
if (!result.Succeeded)
{
 throw new Exception(result.Errors.First().Description);
}
result = userMgr.AddClaimsAsync(bob, new Claim[]{
new Claim(JwtClaimTypes.Role, "Administrator"),
new Claim(JwtClaimTypes.Name, "Bob Smith"),

Running the program, the return value still has no change, which is frustrating and can only continue tossing.
There are studies through the implementation IProfileService Achieve custom Cliams. The article is written in detail, so I won't repeat it. I have actually tried it and it can be successful.

But the attention at the end of the article is very important.

"Then, claims issued by profileservice can be obtained by any clients."

It shows that this priority is very high and can cover all behaviors. Of course, we can IProfileService On the implementation of the authority to step into the setting, but it is still quite troublesome. Reference implementation, reference official

As a lazy person, I don't want to bother to toss about the issue of authority, so is there a simple way?

There are 1 question and answer on the Internet that you can achieve your goal by setting Scopes. But too long ago, IdentityServer4 no longer has this independent class, saying that it has been ApiResource Replaced.

Intuitively, this thing should indicate the related content of API to be protected, which seems to have nothing to do with this, but it can only be a dead horse as a living horse doctor. Modify config. cs, and finally read as follows:


public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
{
 new ApiResource("pls", new[]{ "role"}),
};

public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
 ClientId = "webClient",
 ClientSecrets = { new Secret("secret".Sha256()) },
 AllowOfflineAccess = true,
 AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 // scopes that client has access to
 AllowedScopes = {
 "pls"
 }
},

The result returned is as follows:


{
 "nbf": 1587301799,
 "exp": 1587305399,
 "iss": "http://localhost:5000",
 "aud": "pls",
 "client_id": "webClient",
 "sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
 "auth_time": 1587301799,
 "idp": "local",
 "role": "Administrator",
 "scope": [
 "pls",
 "offline_access"
 ],
 "amr": [
 "pwd"
 ]
}

Finally, I saw the custom Claim (role), and I can visit API.

Note that there is also an Claims in Client, role is added and the AlwaysSendClientClaims And AlwaysIncludeUserClaimsInIdToken After that, it will be added in token client_roie Field, which can't be used and authorized. It can be understood that IdentityServer4 directly specifies the role of Client, not the role concept in Identity.

Postscript

Looking back at the official documents carefully, UserClaims in ApiResource is used for this. After tossing for a long time, it is better to look at the documents carefully at that time.


Related articles: