Как правильно настроить JWT в asp.net core2?
Я пытаюсь применить аутентификацию на основе токена JSON в моем api
приложение. проблема в том, что я получаю недопустимую подпись токена каждый раз, когда проверяю свой токен. более того, я не могу разрешить мой запрос в моих контроллерах, и я думаю, что это может быть связано с генерацией последнего.
Я размещаю весь соответствующий код и буду очень признателен, если кто-нибудь сможет мне помочь. Исходный код получен из github https://github.com/embryologist/ASPNETCore2JwtAuthentication
appsettings.json
"BearerTokens": {
"Key": "iNivDmHLpUA223sqsfhqGbMRdRj1PVkH",
"Issuer": "http://localhost/",
"Audience": "http://localhost/",
"AccessTokenExpirationMinutes": 2,
"RefreshTokenExpirationMinutes": 60
},
Startup.cs / ConfigureServices
services.AddAuthorization(options =>
{
options.AddPolicy(CustomRoles.Admin, policy => policy.RequireRole(CustomRoles.Admin));
options.AddPolicy(CustomRoles.User, policy => policy.RequireRole(CustomRoles.User));
options.AddPolicy(CustomRoles.Editor, policy => policy.RequireRole(CustomRoles.Editor));
});
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg =>
{
cfg.SlidingExpiration = true;
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["BearerTokens:Issuer"],
ValidAudience = Configuration["BearerTokens:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["BearerTokens:Key"])),
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
cfg.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents));
logger.LogError("Authentication failed.", context.Exception);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
var tokenValidatorService = context.HttpContext.RequestServices.GetRequiredService<ITokenValidatorService>();
return tokenValidatorService.ValidateAsync(context);
},
OnMessageReceived = context =>
{
return Task.CompletedTask;
},
OnChallenge = context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents));
logger.LogError("OnChallenge error", context.Error, context.ErrorDescription);
return Task.CompletedTask;
}
};
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.WithOrigins("http://localhost:4200") //Note: The URL must be specified without a trailing slash (/).
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddMvc();
**Startup.cs** / Configure
app.UseAuthentication();
app.UseMvc();
TokenStoreService.cs
public async Task<(string accessToken, string refreshToken)> CreateJwtTokens(ApplicationUser user)
{
var now = DateTimeOffset.UtcNow;
var accessTokenExpiresDateTime = now.AddMinutes(_configuration.Value.AccessTokenExpirationMinutes);
var refreshTokenExpiresDateTime = now.AddMinutes(_configuration.Value.RefreshTokenExpirationMinutes);
var accessToken = await createAccessTokenAsync(user, accessTokenExpiresDateTime.UtcDateTime).ConfigureAwait(false);
var refreshToken = Guid.NewGuid().ToString().Replace("-", "");
await AddUserTokenAsync(user, refreshToken, accessToken, refreshTokenExpiresDateTime, accessTokenExpiresDateTime).ConfigureAwait(false); // this method is only to store the generated token in the database, irrelevent to the issue.
await this.context.SaveChangesAsync();
return (accessToken, refreshToken);
}
private async Task<string> createAccessTokenAsync(ApplicationUser user, DateTime expires)
{
var claims = new List<Claim>
{
// Unique Id for all Jwt tokes
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
// Issuer
new Claim(JwtRegisteredClaimNames.Iss, _configuration.Value.Issuer),
// Issued at
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToUnixEpochDate().ToString(), ClaimValueTypes.Integer64),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim("DisplayName", user.LastName),
// to invalidate the cookie
new Claim(ClaimTypes.SerialNumber, user.SecurityStamp),
// custom data
new Claim(ClaimTypes.UserData, user.Id.ToString())
};
// add roles
var roles = await _rolesService.FindUserRolesAsync(user.Id).ConfigureAwait(false);
foreach (var role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role.RoleId));
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.Value.Key));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _configuration.Value.Issuer,
audience: _configuration.Value.Audience,
claims: claims,
notBefore: DateTime.UtcNow,
expires: expires,
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
Образец сгенерированного токена
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkODFhNTQ.q-IphSwiOhzDT9upOO4XOvGQVp_NxymcuW4WWuERe2U
1 ответ
Так что моя проблема была ошибка в моем ITokenValidatorService
это ваш индивидуальный способ проверки вашего токена.
OnTokenValidated = context =>
{
var tokenValidatorService = context.HttpContext.RequestServices.GetRequiredService<ITokenValidatorService>();
return tokenValidatorService.ValidateAsync(context);
},
Показанный выше конфиг работает просто отлично
Но мне все еще интересно, почему валидатор JWT продолжает возвращать любой отправленный токен как недействительный!