c# - 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,任何用户都可以编辑另一个用户的数据。是否有可能通过令牌以某种方式限制操作,或者这样做更好?
解决方案
您不应该信任用户提交的数据。你应该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 });
}
}
推荐阅读
- unity3d - 如何在激活一个游戏对象并停用另一个游戏对象时从另一个场景加载场景?
- google-apps-script - 将附件从 gMail 保存到 gDrive?
- windows - 如何在 Go 中获取 Windows 显示名称?
- python-3.x - 当您不确切知道要匹配的内容时,可变长度的前瞻/后置正则表达式(python)
- php - 为什么我的 ftp 连接在 php laravel 中不起作用,但在 FileZilla 中起作用?
- c# - Windows 服务触发事件
- html - 预填充输入字段时,HTML 将时间值转换为正确的格式
- amazon-web-services - 我的存储桶是否应该对我的用例公开,我应该如何避免不良做法?
- node.js - 自调用异步函数中的哨兵错误跟踪
- class - 在类中创建 Pygame 表面时出现 ValurError