簡體   English   中英

如何使用從 ajax 調用獲得的 JWT 令牌按 MVC 控制器中的角色授權用戶

[英]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 標頭添加到重定向? 控制器會從令牌中理解用戶角色嗎?

我會很感激你的指導。

好消息是,您實際上甚至在這里有一些選擇。 我是用手機寫的,所以會非常簡潔:

  1. 您可以使用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 中指定。

  2. 使用一些現有的中間件並在您的Startup.ConfigureServices(IServiceCollection)配置 DI。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM