1

I am converting dontcore web API on a new development stack to go serverless using the Azure functions.

I am thinking that my application should use Identity to store user credentials and other details. and he should get authenticated across Identity DataBase and generated using JWT tokens.

I am trying to get hold of some examples that might be helpful to see how to implement JWT in Azure functions.

JWT Token Generation Process

     public UserResponce AuthendicateUser(string username, string password)
        {
            bool valid_user= ValidateUser(username,password);
            if (vlaid_user)
            {

                // authentication successful so generate jwt token
                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.ASCII.GetBytes(_jwtIssuerOptions.Value.JwtKey);
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(new Claim[]
                    {
                    new Claim(ClaimTypes.Name, "1"),
                    new Claim(ClaimTypes.GivenName, username),
                    new Claim(ClaimTypes.Role, UserRoleEnum.superadmin.ToString()),
                    new Claim("hospitalid", "1")
                    }),
                    Expires = DateTime.UtcNow.AddMinutes(_jwtIssuerOptions.Value.JwtExpireMinutes),
                    IssuedAt = DateTime.UtcNow,
                    NotBefore = DateTime.UtcNow,
                    Audience = _jwtIssuerOptions.Value.JwtAuidence,
                    Issuer = _jwtIssuerOptions.Value.JwtIssuer,
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
                };
                var token = tokenHandler.CreateToken(tokenDescriptor);
                string newJwttoken = tokenHandler.WriteToken(token);

                return new UserResponce
                {

                    //HospitalId = user.HospitalId.Value,
                    Token = newJwttoken,
                    UserId = 1,
                    UserName = username,
                    Expires = DateTime.UtcNow.AddMinutes(_jwtIssuerOptions.Value.JwtExpireMinutes),
                };
            }
            else
            {
                return null;
            }

        }

Using Functions like Bellow code, where user, identity values getting Nulls

        var user = req.HttpContext.User;
        var identity = claimsPrincipal.Identity;

Function Code

        [FunctionName("Get_User")]
        public async Task<IActionResult> GetUser(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Globals.UserRoute+"/getuser")] HttpRequest req, ILogger log, ClaimsPrincipal claimsPrincipal)
        {

            log.LogInformation("C# HTTP trigger function processed a request started");
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            AuthendicateModel data = JsonConvert.DeserializeObject<AuthendicateModel>(requestBody);
            var user = req.HttpContext.User;
            var identity = claimsPrincipal.Identity;
            var details = _userService.Username();
            log.LogInformation("C# HTTP trigger function processed a request.");
            return new OkObjectResult(new ApiResponse(HttpStatusCode.OK, details, ResponseMessageEnum.Success.ToString()));

        }
Arturo Martinez
  • 3,737
  • 1
  • 22
  • 35
Ramakrishna.p
  • 1,159
  • 12
  • 31
  • Do you have any other concerns? if you have no other concerns, could you please accept it as an answer(https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)? – Jim Xu Aug 12 '20 at 01:02

2 Answers2

0

No need to validate. Just use this package DarkLoop.Azure.Functions.Authorize

In your startup class initialize authentication:

builder.Services
    .AddFunctionsAuthentication();
    .AddJwtBearer(options => 
     {
        //your JWT configuration here just like in ASPNET Core
     });

builder.Services.AddFunctionsAuthorization();

Then all you need to do is decorate your functions or functions class with FunctionAuthorizeAttribute and you can have the same granular control as in ASPNET WebAPI:

    [FunctionAuthorize]
    [FunctionName("Get_User")]
    public async Task<IActionResult> GetUser(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Globals.UserRoute+"/getuser")] HttpRequest req, ILogger log)
    {

        log.LogInformation("C# HTTP trigger function processed a request started");
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        AuthendicateModel data = JsonConvert.DeserializeObject<AuthendicateModel>(requestBody);
        var user = req.HttpContext.User;
        var identity = user.Identity;
        var claims = user.Claims;
        var details = _userService.Username();
        log.LogInformation("C# HTTP trigger function processed a request.");
        return new OkObjectResult(new ApiResponse(HttpStatusCode.OK, details, ResponseMessageEnum.Success.ToString()));

    }

Configuring authentication this way ensures tokens validation, the same way it happens in ASP.NET Core WebAPI.

You can also take a look at this blog post for reference.

Arturo Martinez
  • 3,737
  • 1
  • 22
  • 35
-1

If you want to validate your jwt token in Azure function, you can use the sdk System.IdentityModel.Tokens.Jwt to implement it. For more details, please refer to here

For example

var authorizationHeader = req.Headers?["Authorization"];
            string[] parts = authorizationHeader?.ToString().Split(null) ?? new string[0];
            string token = string.Empty;
            if (parts.Length == 2 && parts[0].Equals("Bearer"))
                token = parts[1];
            var tokenHandler = new JwtSecurityTokenHandler();
            
            var key = Encoding.ASCII.GetBytes("your jwt key vaule");
            // Validate Token and read claims

            // defile the validation Parameters according to your need
            var validationParameters = new TokenValidationParameters()
            {
                RequireExpirationTime = true,
                IssuerSigningKey= new  SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };

            SecurityToken securityToken;
            try {
                // Validate Token
                ClaimsPrincipal principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
                var name = principal.Identity.Name;
                log.LogInformation($"the name is {name}");
                // read claims
                foreach (var claim in principal.Claims) {
                    // process the claim
                }
            } catch (Exception ex) {
                
                // process exception
                 
            
            }

enter image description here

Besides, if you face the issue about Could not load file or assembly System.IdentityModel.Tokens.Jwt when you run the function, please add the following settings in your .csproj file. For further details, please refer to here and here

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
     <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
  </PropertyGroup>
  .....
</Project>
Jim Xu
  • 21,610
  • 2
  • 19
  • 39