带有身份的ASP.NET Core 5 - 可以用[授权]装饰的访问视图
我花了几个小时试图弄清楚为什么登录成功后无法访问视图。从Chrome工具中,我可以看到200个响应,即产生令牌。然后,如果成功的话,它应该导航到主页,但随后我得到了401(未经授权)。如果我删除[授权]
装饰器或添加[washerAnymous]
它有效,但这不是我想要的。从Swagger中,我看到了相同的行为。即使在401错误之后,令牌仍然存在。请帮忙!
appsettings.json (Hidding Key and Insuer)
"JWTSettings": {
"securityKey": "*********",
"validIssuer": "*********",
"validAudience": "https://localhost:44393",
"expiryInMinutes": 5
}
startup.cs
services.AddDbContext<JonathanKrownContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JonathanKrownArtDb")));
services.AddIdentity<User, IdentityRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<JonathanKrownContext>();
var jwtSettings = Configuration.GetSection("JWTSettings");
services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["validIssuer"],
ValidAudience = jwtSettings["validAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
.GetBytes(jwtSettings.GetSection("securityKey").Value))
};
});
services.AddScoped<JwtHandler>();
public class JwtHandler
{
private readonly IConfiguration configuration;
private readonly IConfigurationSection jwtSettings;
public JwtHandler(IConfiguration configuration)
{
this.configuration = configuration;
jwtSettings = this.configuration.GetSection("JwtSettings");
}
public SigningCredentials GetSigningCredentials()
{
var key = Encoding.UTF8.GetBytes(jwtSettings.GetSection("securityKey").Value);
var secret = new SymmetricSecurityKey(key);
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
}
public List<Claim> GetClaims(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Email)
};
return claims;
}
public JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
{
var tokenOptions = new JwtSecurityToken(
issuer: jwtSettings["validIssuer"],
audience: jwtSettings["validAudience"],
claims: claims,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expiryInMinutes"])),
signingCredentials: signingCredentials);
return tokenOptions;
}
}
[Route("[controller]")]
[ApiController]
public class AccountsController : Controller
{
private readonly UserManager<DataModels.User> userManager;
private readonly IMapper mapper;
private readonly JwtHandler jwtHandler;
public AccountsController(UserManager<DataModels.User> userManager, IMapper mapper, JwtHandler jwtHandler)
{
this.userManager = userManager;
this.mapper = mapper;
this.jwtHandler = jwtHandler;
}
[HttpPost("Registration")]
public async Task<IActionResult> RegisterUser([FromBody] DomainModels.User userForRegistration)
{
if(userForRegistration == null || !ModelState.IsValid)
{
return BadRequest();
}
var user = mapper.Map<DataModels.User>(userForRegistration);
var result = await userManager.CreateAsync(user, userForRegistration.Password);
if(!result.Succeeded)
{
var errors = result.Errors.Select(e => e.Description);
return BadRequest(new DomainModels.RegistrationResponse { Errors = errors });
}
return StatusCode(201);
}
[HttpPost("Login")]
public async Task<IActionResult> Login([FromBody] UserForAuthentication userForAuthentication)
{
var user = await userManager.FindByNameAsync(userForAuthentication.Email);
if(user == null || !await userManager.CheckPasswordAsync(user, userForAuthentication.Password))
{
return Unauthorized(new AuthResponse { ErrorMessage = "Invalid Authentication" });
}
var signinCredentials = jwtHandler.GetSigningCredentials();
var claims = jwtHandler.GetClaims(user);
var tokenOptions = jwtHandler.GenerateTokenOptions(signinCredentials, claims);
var token = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
return Ok(new AuthResponse { IsAuthSuccessful = true, Token = token });
}
}
。
[Route("[controller]")]
[Authorize]
[ApiController]
public class PaintingsController : Controller
{
private readonly IPaintingRepository repository;
private readonly IMapper mapper;
private readonly ILogger<PaintingsController> logger;
private readonly IImageRepository imageRepository;
public PaintingsController(IPaintingRepository repository, IMapper mapper, ILogger<PaintingsController> logger, IImageRepository imageRepository)
{
this.repository = repository;
this.mapper = mapper;
this.logger = logger;
this.imageRepository = imageRepository;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
public async Task<IActionResult> GetAllPaintingsAsync()
{
try
{
var claims = User.Claims;
var paintings = await repository.GetHomePagePaintingsAsync();
var paintingsDto = mapper.Map<List<Painting>>(paintings);
return Ok(paintingsDto);
}
catch (Exception ex)
{
logger.LogError($"Failed to get paintings: {ex}");
return BadRequest("Failed to get paintings");
}
}
}
“ alt =”令牌仍然存在,即使在401错误之后”>
I’ve spent hours trying to figure out why I can’t access a view after login is successful. From the Chrome tools I can see a 200 response, token being generated. Then it should navigate to the home page if successful, which it tries, but then I get a 401 (Unauthorized). If I remove the [Authorize]
decorator or add an [AllowAnonymous]
it works but that is not what I am looking for. From swagger I see the same behavior. Token persists even after the 401 error. Please help!
appsettings.json (hidding key and issuer)
"JWTSettings": {
"securityKey": "*********",
"validIssuer": "*********",
"validAudience": "https://localhost:44393",
"expiryInMinutes": 5
}
Startup.cs
services.AddDbContext<JonathanKrownContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JonathanKrownArtDb")));
services.AddIdentity<User, IdentityRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<JonathanKrownContext>();
var jwtSettings = Configuration.GetSection("JWTSettings");
services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["validIssuer"],
ValidAudience = jwtSettings["validAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
.GetBytes(jwtSettings.GetSection("securityKey").Value))
};
});
services.AddScoped<JwtHandler>();
JwtHandler.cs
public class JwtHandler
{
private readonly IConfiguration configuration;
private readonly IConfigurationSection jwtSettings;
public JwtHandler(IConfiguration configuration)
{
this.configuration = configuration;
jwtSettings = this.configuration.GetSection("JwtSettings");
}
public SigningCredentials GetSigningCredentials()
{
var key = Encoding.UTF8.GetBytes(jwtSettings.GetSection("securityKey").Value);
var secret = new SymmetricSecurityKey(key);
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
}
public List<Claim> GetClaims(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Email)
};
return claims;
}
public JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
{
var tokenOptions = new JwtSecurityToken(
issuer: jwtSettings["validIssuer"],
audience: jwtSettings["validAudience"],
claims: claims,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expiryInMinutes"])),
signingCredentials: signingCredentials);
return tokenOptions;
}
}
AccountsController.cs
[Route("[controller]")]
[ApiController]
public class AccountsController : Controller
{
private readonly UserManager<DataModels.User> userManager;
private readonly IMapper mapper;
private readonly JwtHandler jwtHandler;
public AccountsController(UserManager<DataModels.User> userManager, IMapper mapper, JwtHandler jwtHandler)
{
this.userManager = userManager;
this.mapper = mapper;
this.jwtHandler = jwtHandler;
}
[HttpPost("Registration")]
public async Task<IActionResult> RegisterUser([FromBody] DomainModels.User userForRegistration)
{
if(userForRegistration == null || !ModelState.IsValid)
{
return BadRequest();
}
var user = mapper.Map<DataModels.User>(userForRegistration);
var result = await userManager.CreateAsync(user, userForRegistration.Password);
if(!result.Succeeded)
{
var errors = result.Errors.Select(e => e.Description);
return BadRequest(new DomainModels.RegistrationResponse { Errors = errors });
}
return StatusCode(201);
}
[HttpPost("Login")]
public async Task<IActionResult> Login([FromBody] UserForAuthentication userForAuthentication)
{
var user = await userManager.FindByNameAsync(userForAuthentication.Email);
if(user == null || !await userManager.CheckPasswordAsync(user, userForAuthentication.Password))
{
return Unauthorized(new AuthResponse { ErrorMessage = "Invalid Authentication" });
}
var signinCredentials = jwtHandler.GetSigningCredentials();
var claims = jwtHandler.GetClaims(user);
var tokenOptions = jwtHandler.GenerateTokenOptions(signinCredentials, claims);
var token = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
return Ok(new AuthResponse { IsAuthSuccessful = true, Token = token });
}
}
PaintingsController.cs
[Route("[controller]")]
[Authorize]
[ApiController]
public class PaintingsController : Controller
{
private readonly IPaintingRepository repository;
private readonly IMapper mapper;
private readonly ILogger<PaintingsController> logger;
private readonly IImageRepository imageRepository;
public PaintingsController(IPaintingRepository repository, IMapper mapper, ILogger<PaintingsController> logger, IImageRepository imageRepository)
{
this.repository = repository;
this.mapper = mapper;
this.logger = logger;
this.imageRepository = imageRepository;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
public async Task<IActionResult> GetAllPaintingsAsync()
{
try
{
var claims = User.Claims;
var paintings = await repository.GetHomePagePaintingsAsync();
var paintingsDto = mapper.Map<List<Painting>>(paintings);
return Ok(paintingsDto);
}
catch (Exception ex)
{
logger.LogError(quot;Failed to get paintings: {ex}");
return BadRequest("Failed to get paintings");
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论