问题
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?
回答1:
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 });
}
}
来源:https://stackoverflow.com/questions/60622911/security-user-actions-in-asp-net-core-web-api