我正在开发一个ASP.NET Core MVC项目,我正在放置一个基本的MVC网站,还有一个WebApi控制器来处理来自视图的每个调用。
我并没有真正使用整个MVC工作流程,只有路由和授权部分,视图是用简单的javascript和html编写的,因此ASP.NET MVC中没有像标记帮助器或模型那样的元素。
在第一个索引页面中,我有一个登录表单,它在WebApi控制器中调用(使用jquery)一个操作,如果用户和密码有效,我使用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标头添加到重定向?控制器是否会从令牌中了解用户角色?
我将非常感谢您的指导
答案 0 :(得分:0)
好消息是你实际上甚至有一些选择。我是用手机写的,所以它会非常简洁:
您可以使用ServiceFilterAttribute
指定执行JWT解析的CustomJwtAuthorizationFilter
,提取声明并具体化 IPrincipal.Identity
受保护的控制器中的User
保护,如下所示:
[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
来明确区分代表角色的声明,这在大多数情况下应默认为"role"
}! 。但是这几乎应该透明地完成,因为角色声称应该在JWT中指定。
使用一些现有的中间件并在Startup.ConfigureServices(IServiceCollection)
配置DI。