首页 > 解决方案 > ASP.Net Core Web API 中的安全用户操作

问题描述

我使用 JWT 令牌在 ASP.Net Core Web API 中创建用于测试身份验证的项目。我实现了使用帐户的基本功能,但遇到了一些问题。

用户控制器:

[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);
    }
}

身份验证服务:

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();
}

事实证明,授权后,如果我们在发送请求的客户端中指定不同的 id,任何用户都可以编辑另一个用户的数据。是否有可能通过令牌以某种方式限制操作,或者这样做更好?

标签: c#securityasp.net-core-webapijwt-auth

解决方案


您不应该信任用户提交的数据。你应该UserId像你自己做的那样设置有效载荷数据

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

JWT当用户编辑数据时,像这样获取用户ID

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);
}

或者

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

最后

[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 });
    }
}


推荐阅读