Search code examples
asp.net-web-apiasp.net-coreasp.net-identityasp.net-core-webapiasp.net-core-identity

ASP.NET Core Secure Api


I have an ASP.NET Core project that has a Web API for mobile device (Xamarin). I want to secure the api with ASP.NET Core identity, but the problem is when I authenticate a device and authenticated successfully, in another request it not still authenticated:

[HttpPost]
public async Task<IActionResult> Post([FromBody] LogIn l)
{
    var user = await userManager.FindByEmailAsync(l.username);

    if(user == null)
    {
        user = await userManager.FindByNameAsync(l.username);
    }

    if(user != null)
    {
        await signInManager.SignOutAsync();
        Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(user, l.password, false, false);

        if (result.Succeeded)
        {
            await signInManager.RememberTwoFactorClientAsync(user);

            return Ok("Success");
        }
    }

    return Ok(HttpStatusCode.BadRequest);
}

The code that needs to authorize to return data :

[HttpGet("{id}")]
[Authorize]
public async Task<IActionResult> Get(int id)
{
    var b = _context.Books.FirstOrDefault(o => o.BookId == id);
    return Ok(b);
}

I read about token and jwt but I don't know how to use them. Any Idea how to secure the API and make the device authenticated once they log in?


Solution

  • I know it's late, but I think the idea is to login the user, and return a token that's then saved to the client's(Xamarin Android/iOS for your case) local storage/Sharedpreferences. The saved token can then be used for subsequent Web API calls for authentication without the need to login. It can then be cleared when a user logs out. For JWT, you can restructure your login function as follows:

    var token = await GetJwtSecurityToken(user);
     return Ok(new
            {
             token = new JwtSecurityTokenHandler().WriteToken(token),
                    expiration = token.ValidTo
            });
    

    The GetJwtSecurityToken() can look like this depending on your needs:

     private async Task<JwtSecurityToken> GetJwtSecurityToken(ApplicationUser user)
            {
                var userClaims = await _userManager.GetClaimsAsync(user);
    
                return new JwtSecurityToken(
                    //issuer: "http://localhost:****/",                
                    //audience: "http://localhost:****/",
                    audience: "http://localhost:****/",
                    claims: GetTokenClaims(user).Union(userClaims),//Combine user & claims
                    //expires: DateTime.UtcNow.AddMinutes(10),
                    signingCredentials: new SigningCredentials(new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("x%u<-Q.@w^:qF]2Hz4")), SecurityAlgorithms.HmacSha256)
                );
            }
    

    The GetTokenClaims() function can look like:

    private static IEnumerable<Claim> GetTokenClaims(ApplicationUser user)
        {
            return new List<Claim>
            {
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim("UserName", user.UserName),
            new Claim("Email", user.Email),
            new Claim(JwtRegisteredClaimNames.Sub, user.Id),
            new Claim("FirstName", user.FirstName)
            //Other user info
            };
        } 
    

    You can then save this token in local storage/Sharedpreferences, and use it to authenticate your API calls. You can research on: How to decode JWT token in Xamarin, OpenId..

    Let me know how it goes.