1

I have asp.net core identity server with grpc and a asp.net core api and i what to when user sends a request with jwt token to the asp.net core api the jwt token goes to my custom authorize attribute and in my custom authorize attribute i send the jwt token to my identity server with grpc and at the response identity server give me roles and has access that is true and after that i store roles and token in the redis database so every time if token was in redis no need to send a request to identity server so i don't know how to Handel it should my attribute use Authorization Filter or authorization handler and my grpc server is ready i request to my grpc service

AuthorizationGrpcServices.ValidateToken(string token)

and the result is this like this

bool access = true 
string roles = " Admin , User "

so i need custom attribute that use redis and this grpc service

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
regestea23
  • 456
  • 6
  • 19
  • 1
    Have you tried any of [these ways](https://stackoverflow.com/questions/31464359/how-do-you-create-a-custom-authorizeattribute-in-asp-net-core)? – Chen Feb 20 '23 at 09:26

1 Answers1

0

You can do this by custom attribute

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]

public class AuthorizeByIdentityServer : ActionFilterAttribute, IAsyncActionFilter
{

    private readonly string? requiredRoles;

    public AuthorizeByIdentityServer(string? requiredRoles = null)
    {
        this.requiredRoles = requiredRoles;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        
        var authorizationGrpcServices =
            context.HttpContext.RequestServices.GetService<AuthorizationGrpcServices>() ??
            throw new ArgumentNullException(nameof(AuthorizationGrpcServices));

        var tokenCache = context.HttpContext.RequestServices.GetService<ICacheRepository>() ??
                         throw new ArgumentNullException(nameof(ICacheRepository));


        if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var authorizationHeader))
        {
            context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized);
            return;
        }

        var jwtToken = authorizationHeader.ToString().Replace("Bearer ", "");

        ValidateTokenResponse? response;

        // try to get token and roles from cache
        response = await tokenCache.GetAsync<ValidateTokenResponse>(jwtToken);

        if (response == null)
        {
            response = await authorizationGrpcServices.ValidateTokenAsync(jwtToken);
            if (response.Valid)
            {
                await tokenCache.SetAsync(jwtToken, response, TimeSpan.FromHours(3));
            }
        }

        if (!response.Valid)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized);
            return;
        }

        if (requiredRoles == null)
        {
            await next();
            return;
        }

        //check user role for required roles
        var roleList = response.Roles.Split(",");
        var requiredRoleList = requiredRoles.Split("|");

        foreach (var requiredRoleGroup in requiredRoleList)
        {
            var requiredRoleSubList = requiredRoleGroup.Split(",");
            var hasRequiredRole = true;

            foreach (var requiredRole in requiredRoleSubList)
            {
                if (!roleList.Any(x => x == requiredRole))
                {
                    hasRequiredRole = false;
                    break;
                }
            }

            if (hasRequiredRole)
            {
                await next();
                return;
            }
        }

        context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
        return;
    }
}

and you can use this custom attribute like this

    [AuthorizeByIdentityServer] //no need for role
    [AuthorizeByIdentityServer("User")] // required user role
    [AuthorizeByIdentityServer("User,Admin")]// required user role and admin role
    [AuthorizeByIdentityServer("User|Admin")] // required user role or admin role
regestea23
  • 456
  • 6
  • 19