简体   繁体   中英

Security user actions in ASP.Net Core Web API

I create project for test authentication in ASP.Net Core Web API with using JWT tokens. I implemented the basic functionality for working with accounts, but I ran into some problems.

UsersController:

[Authorize]
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly IAuthenticationService _authenticationService;

    public UsersController(
        IUserService userService,
        IAuthenticationService authenticationService)
    {
        _userService = userService;
        _authenticationService = authenticationService;
    }

    // PUT: users/5
    [HttpPut("{id}")]
    public async Task<ActionResult> PutUser(int id, [FromBody]UpdateUserModel model)
    {
        try
        {
            var user = await _userService.UpdateAsync(model, id);

            return Ok();
        }
        catch(Exception ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    // POST : users/authenticate
    [AllowAnonymous]
    [HttpPost("authenticate")]
    public async Task<ActionResult<User>> Authenticate([FromBody] AuthenticateUserModel model)
    {
        var user = await _authenticationService.AuthenticateAsync(model);

        if (user == null)
            return BadRequest(new { message = "Login or password is incorrect" });

        return Ok(user);
    }
}

AuthenticationService:

public async Task<User> AuthenticateAsync(AuthenticateUserModel model)
{
    var users = await _context.Users.ToListAsync();
    var user = users.SingleOrDefault(x => x.Login == model.Login && x.Password == model.Password);

    if (user == null)
        return null;

    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[]
        {
            new Claim(ClaimTypes.Name, user.Id.ToString()),
            new Claim(ClaimTypes.Role, user.Role)
        }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    user.Token = tokenHandler.WriteToken(token);

    return user.WithoutPassword();
}

It turns out that after authorization, any user can edit the data of another user if we specify a different id in the client who will send requests. Is it possible to somehow limit the actions thanks to the token or how is it better to do this?

You should't trust the submitted data from the user . you should set UserId in payload data like what you did yourself

 new Claim(ClaimTypes.Name, user.Id.ToString()),

and when user edit the data get user id from JWT like this

public int GetCurrentUserId()
{
    var claimsIdentity = _contextAccessor.HttpContext.User.Identity as ClaimsIdentity;
    var userDataClaim = claimsIdentity?.FindFirst(ClaimTypes.Name);
    var userId = userDataClaim?.Value;
    return string.IsNullOrWhiteSpace(userId) ? 0 : int.Parse(userId);
}

or

int userId = Convert.ToInt32((User.Identity as ClaimsIdentity).FindFirst(ClaimTypes.Name).Value);

and finally

[HttpPut("PutUser")]
public async Task<ActionResult> PutUser([FromBody]UpdateUserModel model)
{
    try
    {
        int userId = Convert.ToInt32((User.Identity as ClaimsIdentity).FindFirst(ClaimTypes.Name).Value);
        var user = await _userService.UpdateAsync(model, userId);
        return Ok();
    }
    catch (Exception ex)
    {
        return BadRequest(new { message = ex.Message });
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM