Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core 2.0 Identity AND jwt?

I've been looking around and trying to do more research on .NET Core Identity (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.1&tabs=visual-studio%2Caspnetcore2x) and Jwt (json web tokens). I've been rolling with the default Identity as authentication/authorization in my .NET Core 2.0 app and it has been working well so far.

I'm running into a roadblock and I think it's the way of my understanding of .NET Core identity and jwt. My application has MVC and an web api. I would ideally like to secure the web api, but I hear the best way to do that now is through jwt. Good - cool.

I can go ahead and configure jwt and then use it as my authentication/authorization (https://blogs.msdn.microsoft.com/webdev/2017/04/06/jwt-validation-and-authorization-in-asp-net-core/), but - do I need to go ahead and spin up a new server to serve as the authorization server for jwt? If so, I'm not going to do that (too expensive).

What about my .NET Core identity code if I do go with jwt? Does that have to go away then? If it can co-exist, how might I authorize my MVC pages with Identity and my api endpoints with jwt?

I realize this is an open-ended question, but the core of it is:

Can .NET Core Identity and JWT co-exist? Or do I have to choose one or the other? I have MVC and an web api and would like to secure both.

like image 287
reZach Avatar asked Jul 13 '18 02:07

reZach


Video Answer


2 Answers

Yes, you can. The logic process is in this method:

Step 1: GetUserClaims

var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password);

  • Into GetClaimsIdentity you will

    private async Task<ClaimsIdentity> GetClaimsIdentity(string userName, string password)
    {
        if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
            return await Task.FromResult<ClaimsIdentity>(null);
    
        var userToVerify = await _userManager.FindByNameAsync(userName);                
    
        if (userToVerify == null) {
            userToVerify = await _userManager.FindByEmailAsync(userName);
            if (userToVerify == null)  {
                return await Task.FromResult<ClaimsIdentity>(null);
            }
        }
        // check the credentials
        if (await _userManager.CheckPasswordAsync(userToVerify, password))
        {
            _claims = await _userManager.GetClaimsAsync(userToVerify);
    
            return await Task.FromResult(_jwtFactory.GenerateClaimsIdentity(userToVerify.UserName, userToVerify.Id, _claims));
        }
        // Credentials are invalid, or account doesn't exist
        return await Task.FromResult<ClaimsIdentity>(null);
    }
    

Step 2: Group all user claims you need add to the token - Use System.Security.Claims

 public ClaimsIdentity GenerateClaimsIdentity(string userName, string id, IList<Claim> claims)
    {
        claims.Add(new Claim(Helpers.Constants.Strings.JwtClaimIdentifiers.Id, id));

        // If your security is role based you can get then with the RoleManager and add then here as claims

        // Ask here for all claims your app need to validate later 

        return new ClaimsIdentity(new GenericIdentity(userName, "Token"), claims);
    }

Step 3: Then back on your method you have to generate and return the JWT Token

jwt = await jwtFactory.GenerateEncodedToken(userName, identity);
return new OkObjectResult(jwt);
  • To generate token do something like this:

    public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
    {
        List<Claim> claims = new List<Claim>();
        //Config claims
        claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName));
        claims.Add(new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()));
        claims.Add(new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64));
        //End Config claims
        claims.AddRange(identity.FindAll(Helpers.Constants.Strings.JwtClaimIdentifiers.Roles));
        claims.AddRange(identity.FindAll("EspecificClaimName"));
    
    
        // Create the JWT security token and encode it.
        var jwt = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims: claims,
            notBefore: _jwtOptions.NotBefore,
            expires: _jwtOptions.Expiration,
            signingCredentials: _jwtOptions.SigningCredentials);
    
        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
    
        return encodedJwt;
    }
    

There are many ways to do this. The most common is: Validate Identity User --> Get User identifiers --> Generate and Return Token Based on Identifiers --> Use Authorization for endpoints

Hope this help

like image 136
Daniel Aguilar Avatar answered Oct 11 '22 18:10

Daniel Aguilar


You can validate the username and password and generate the Jwt.

First, make sure your API has the following default identity set up in the startup.cs:

services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(
        Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Secondly, you can validate the login with something like this:

You can set up an API controller something like this:

[ApiController, Route("check")]
public class TokenController : ControllerBase
{
    private readonly SignInManager<IdentityUser> signin;

    public TokenController(SignInManager<IdentityUser> signin)
    {
        this.signin = signin;
    }

    [HttpGet]
    public async Task<string> Get(string user, string pass)
    {
        var result = await signin.PasswordSignInAsync(user, pass, true, false);
        if (result.Succeeded)
        {
            string token = "";
            return token;
        }
        return null;
    }
}

Within your get function, you can now generate your Jwt.

like image 30
Neville Nazerane Avatar answered Oct 11 '22 20:10

Neville Nazerane