[英]How to authorize users by role in MVC Controllers using a JWT token obtained from ajax call
我正在處理一個 ASP.NET Core MVC 項目,我在其中放置了一個基本的 MVC 網站和一個 WebApi 控制器來處理來自視圖的每個調用。
我並沒有真正使用整個 MVC 工作流,只有路由和授權部分,視圖是用純 javascript 和 html 編寫的,所以沒有來自 ASP.NET MVC 的元素,如標簽助手或模型。
在第一個索引頁面中,我有一個登錄表單,它調用(使用 jquery)WebApi 控制器中的一個操作,在那里我使用 ASP.NET Identity Core 來授權用戶,如果用戶和密碼有效,我將返回一個JWT 令牌。
[Produces("application/json")]
[Route("api/[controller]")]
[AllowAnonymous]
[ApiController]
public class AccountController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<AccountController> logger,
IConfiguration configuration)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_configuration = configuration;
}
[Route("test")]
[HttpGet]
public async Task<IActionResult> Test()
{
return Ok(await Task.FromResult("Endpoint working"));
}
[Route("login")]
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginDto model)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);
if (result.Succeeded)
{
var appUser = _userManager.Users.SingleOrDefault(r => r.Email == model.Email);
return Ok(await GenerateJwtToken(model.Email, appUser));
}
return BadRequest(string.Empty);
}
[Route("logout")]
[HttpGet]
public async Task Logout()
{
await _signInManager.SignOutAsync();
}
private async Task<object> GenerateJwtToken(string email, IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"]));
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: expires,
signingCredentials: creds
);
return await Task.FromResult(new JwtSecurityTokenHandler().WriteToken(token));
}
}
這部分工作正常,在數據庫中我有幾個用戶有自己的角色。 問題是,登錄后,我想將用戶重定向到具有由角色保護的操作的 MVC 控制器,控制器如下所示:
public class SecuredController : Controller
{
[Authorize]
public IActionResult Index()
{
return View();
}
[Authorize(Roles = "Role1, Admin")]
public IActionResult Register()
{
return View();
}
[Authorize(Roles = "Role2, Admin")]
public IActionResult Fraud()
{
return View();
}
}
登錄后我正在做類似的事情
window.location = '@Url.Action("Index", "Secured")'
但我總是收到 401 響應。
是否可以將帶有令牌的 Authorization 標頭添加到重定向? 控制器會從令牌中理解用戶角色嗎?
我會很感激你的指導。
好消息是,您實際上甚至在這里有一些選擇。 我是用手機寫的,所以會非常簡潔:
您可以使用ServiceFilterAttribute
指定一個CustomJwtAuthorizationFilter
來執行 JWT 的解析、提取聲明並具體化IPrincipal.Identity
以綁定到安全控制器中的User
protenty,如下所示:
[ServiceFilter(typeof(CustomJwtAuthorizationFilter))] public class SecuredController : Controller { ... } public class CustomJwtAuthorizationFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext actionContext) { // get claims out of JWT in the request's Authorization header var claims = ... var identity = new ClaimsIdentity(claims); actionContext.HttpContext.User = new ClaimsPrincipal(identity); ... } }
這里的技巧是通過將ClaimType
屬性設置為配置的RoleClaimType
來確保明確區分代表角色的RoleClaimType
,在大多數情況下,默認情況下應該是"role"
!!! 😄。 但這是應該幾乎透明地完成的事情,因為角色聲明應該在 JWT 中指定。
使用一些現有的中間件並在您的Startup.ConfigureServices(IServiceCollection)
配置 DI。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.