0

I am using jwt tokens in my project. When the client logins, he will receive a token with his device id (in mobile) -that was sent to the server in the request body- as the payload...

The thing I want to do is for further requests when the client sends his device id in the body (as a convention in my project) and of course the token in the header request, I want to check if the device id and the token's payload are equal or not.

I did this in a service like this:

public class AuthenticationService
{
    public bool IsAuthenticated(HttpRequest req, string deviceId)
    {


        var token = req.Headers["authorization"];
        var handler = new JwtSecurityTokenHandler();

        JwtSecurityToken tokenS;  

        foreach (var stringValue in token)
        {
            var ss = stringValue.Replace("Bearer ", "");
            if (handler.CanReadToken(ss))
            {
                tokenS = handler.ReadToken(ss) as JwtSecurityToken;
                return tokenS.Claims.Any(c => c.Value == deviceId);

            }
        }

        return false;
    }
}

And I should inject it in every controller that I want to authorize the user...

if (_authenticationService.IsAuthenticated(Request, deviceId))
        {
            _logger.LogInformation("authorized!");
        }
        else
        {
            _logger.LogCritical("unauthorized");
        }

I want to know that if there is a more cleaner way of doing this? Something to do in the Startup class when I'm configuring the Authentication:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(
                        Configuration.GetSection("AppSettings:Token").Value)),
                    ValidateIssuer = false,
                    ValidateAudience = false,

                };
            });
  • You could use a `Base Controller` which is inherited by all your other controllers, and then override `OnActionExecuting` to validate the user before processing the request. This would cut down on boilerplate code. – Ryan Wilson Feb 04 '20 at 15:39
  • Why not do it in the request pipeline , insted of every controller... – Soumen Mukherjee Feb 04 '20 at 15:40

1 Answers1

1

AddJwtBearer extension will map the claims in token to user's cliams , you can get the device ID by (if cliam type is deviceId):

var deviceID= context.HttpContext.User.Claims.Where(x => x.Type == "deviceId").FirstOrDefault().Value;

Then you can use Filter or Middleware to read request body and compare the device ID in reuqest body with the one in User's claim . For example , if using Filter :

public class CustomActionFilter : ActionFilterAttribute
{
    public override async void OnActionExecuting(ActionExecutingContext context)
    {

        if (context.HttpContext.User.Identity.IsAuthenticated) { 

        //read request body 
        var bodyStr = "";
        var req = context.HttpContext.Request;
        req.EnableBuffering();
        req.Body.Position = 0;
        using (var stream = new StreamReader(req.Body))
        {
            bodyStr = await stream.ReadToEndAsync();
        }

        // here you get device ID from bodyStr ,for example : deviceIDFromReq

        var deviceID= context.HttpContext.User.Claims.Where(x => x.Type == "deviceId").FirstOrDefault().Value;

        // then compare 

        if (deviceIDFromReq.Equals(deviceID))
        {
            context.Result = new BadRequestObjectResult(new
            {
                status = "error",
                description = "deviceID not matched"
            });
        }
        }
        base.OnActionExecuting(context);
    }
}

Register as global filter :

services.AddControllers(config =>
{
    config.Filters.Add<CustomActionFilter>();

});
Nan Yu
  • 26,101
  • 9
  • 68
  • 148
  • That depends on how you send the device id in request , put checkpoint on `bodyStr ` to confirm it , use string spilt or json.net to convert json string to object . like [here](https://stackoverflow.com/a/13116824/5751404)and [here](https://stackoverflow.com/a/48733551/5751404) – Nan Yu Feb 06 '20 at 08:20