2021年1月23日 星期六

[ASP.NET Core] Identity Server 4 - Get authorized user claims

   ASP.NET Core   JW  Claims  






Introduction

 

Sometimes we want to get the user’s information by JWT before go inside the API controller/action.

For example, verify the JWT claim(s) or even overwrite the payload.

 

In this short article, we will create a custom Action Filter which inherits/implements Attribute and IAsyncActionFilter that can:

 

·         Get user claims.

·         Also: Get Http request’s request and modify it.

·         Also: Save custom items to HttpContext.

 

 

 

Related articles

 

01.      [OpenLDAP] Create an OpenLDAP container

02.      [ASP.NET Core] Identity Server 4 – Concepts

03.      [ASP.NET Core] Identity Server 4 – LDAP authentication

04.      [ASP.NET Core] Identity Server 4 – Secure Web API

05.      [ASP.NET Core] Identity Server 4 – Custom Event Sink

06.      [ASP.NET Core] Identity Server 4 – Refresh Token

07.      [ASP.NET Core] Identity Server 4 – Role based authorization

08.      [ASP.NET Core] Identity Server 4 – Policy based authorization

09.      [ASP.NET Core] Identity Server 4 - Dockerize

10.      [ASP.NET Core] Identity Server 4 – Client Credential

11.      [ASP.NET Core] Identity Server 4 – Policy based authorization with custom Authorization Handler

12.      [ASP.NET Core] Identity Server 4 – Signing credential

13.      [ASP.NET Core] Identity Server 4 – Authenticate by multiple LDAP

14.      [ASP.NET Core] Identity Server 4 – Cache and refresh Discovery document

15.      [ASP.NET Core] Identity Server 4 – PKCE Authorization Code Flow

16.      [ASP.NET Core] Identity Server 4 – PKCE Authorization Code Flow (Javascript client)

 .NET Core] Identity Server 4 – Get .NET Core] Identity Server 4 – Get authorized user claims

 [ASP.NET Core] Identity Server 4 – Get authorized user claims

[ASP.NET Core] Identity Server 4 – Get authorized use

 

Environment

 

Docker 18.05.0-ce

ASP.NET Core 3.1.300

IdentityServer4 3.1.2

IdentityModel 3.10.10

 

 

 

Implement

 

The source code is on my Github.

 

Create User Profile filter

 

There are two ways to get the user’s claims:

 

1.  Use System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler to decode the JWT.

2.  Use the System.Security.ClaimsPrinciple from HttpContext.

 

UserProfileFilter


public class UserProfileFilter : AttributeIAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext contextActionExecutionDelegate next)
    {
        string uid = string.Empty;
        string email = string.Empty;
        StringValues authHeaderVal = default(StringValues);

        // Method 1. Use System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler to decode the JWT.
        if (context.HttpContext.Request.Headers.TryGetValue("Authorization"out authHeaderVal))
        {
            string bearerTokenPrefix = "Bearer";
            string accessToken = string.Empty;
            string authHeaderStr = authHeaderVal.ToString();
            if (!string.IsNullOrEmpty(authHeaderStr) && authHeaderStr.StartsWith(bearerTokenPrefixStringComparison.OrdinalIgnoreCase))
            {
                accessToken = authHeaderStr.Replace(bearerTokenPrefixstring.EmptyStringComparison.OrdinalIgnoreCase).Trim();
            }

            var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
            var token = handler.ReadJwtToken(accessToken);
            uid = token.Claims.FirstOrDefault(c => c.Type.Equals("sub"StringComparison.OrdinalIgnoreCase))?.Value;
            email = token.Claims.FirstOrDefault(c => c.Type.Equals(JwtClaimTypes.Email))?.Value;
        }

        // 2. Use the System.Security.ClaimsPrinciple from HttpContext.
        var user = context.HttpContext.User;
        if (user.Identity.IsAuthenticated)
        {
            uid = user.Claims.FirstOrDefault(c => c.Type.Equals("sub"StringComparison.OrdinalIgnoreCase))?.Value;
            email = user.Claims.FirstOrDefault(c => c.Type.Equals(JwtClaimTypes.Email))?.Value;
        }
        
        await next();
    }
}



The above sample code shows how to get user’s sub and email claims.

 

 

Use it in Controller/Action

 


 [HttpGet("UserProfile")]
 [Authorize]
 [TypeFilter(typeof(UserProfileFilter))]
 public async Task<IActionResultUserProfile()
 {
     return this.Ok();
 }

 



Also: Get request’s payload and modify it

 

We can use ActionArguments to get the payload object of a Http request and modify it before the payload get into the Controller’s Action.

 

UserProfileFilter

 

 public class UserProfileFilter : AttributeIAsyncActionFilter
 {
    public async Task OnActionExecutionAsync(ActionExecutingContext contextActionExecutionDelegate next)
    {
            // ...skip

            MyPayload payload = (MyPayload)context.ActionArguments?.Values.FirstOrDefault(v => v is RequestDto);
            payload.Uid = uid;
            
            await next();
    }
 }

 




Also: Save custom items to HttpContext

 

Once we what to keep some information on the current request, we can easily save them as HttpContext items and get them later inside Controller’s Action.

 

UserProfileFilter


public class UserProfileFilter : AttributeIAsyncActionFilter    
{
    public async Task OnActionExecutionAsync(ActionExecutingContext contextActionExecutionDelegate next)
    {
        // ...skip
        string itemName = "UserProfile";
        context.HttpContext.Items.Add(itemNamenew { Id = uidEmail = email });
            
        await next();
    }
 }

 

 

Now we can get the items as following,

 

Controller


[HttpGet("UserProfile")]
 [TypeFilter(typeof(UserProfileFilter))]
 public async Task<IActionResultUserProfile()
 {
     if (this.HttpContext.Items.TryGetValue("UserProfile"out object userProfile))
     {
         this.logger.LogInformation(JsonConvert.SerializeObject(userProfile));
     }
     
return this.Ok();
 }



  

Source Code

 

Github: KarateJB/AspNetCore.IdentityServer4.Sample

 

 

 

Reference

 

Overwrite request object in ASP .NET Core

 

 

 

沒有留言:

張貼留言