我知道這是一個常見問題,但是當我搜索類似主題時,我找不到任何解決方案。
我創建了一個帶有 JWT 授權的簡單 API,但是,在向[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]我的控制器添加標簽后,每個請求(即使在 Swagger 中添加了 JWT 令牌)都會拋出 401。
JWT 的配置如下:
var jwtSettings = new JwtSettings();
configuration.Bind(nameof(jwtSettings), jwtSettings);
services.AddSingleton(jwtSettings);
services.AddScoped<IIdentityService, IdentityService>();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret)),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
};
});
啟動類如下所示:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
var swaggerOptions = new SwaggerOptions();
Configuration.GetSection(nameof(SwaggerOptions)).Bind(swaggerOptions);
app.UseSwagger(option =>
{
option.RouteTemplate = swaggerOptions.JsonRoute;
});
app.UseSwaggerUI(option =>
{
option.SwaggerEndpoint(swaggerOptions.UIEndpoint, swaggerOptions.Description);
});
app.UseHttpsRedirection();
app.UseStaticFiles();
//this is correct order
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
令牌生成方法如下所示:
public async Task<AuthenticationResult> RegisterAsync(string email, string password)
{
var existingUser = await _userManager.FindByEmailAsync(email);
if (existingUser != null)
{
return new AuthenticationResult
{
Errors = new[] { "User with this e-mail address already exists" }
};
}
var newUser = new IdentityUser
{
Email = email,
UserName = email
};
var createdUser = await _userManager.CreateAsync(newUser, password);
if (!createdUser.Succeeded)
{
return new AuthenticationResult
{
Errors = createdUser.Errors.Select(x => x.Description)
};
}
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, newUser.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, newUser.Email),
new Claim("id", newUser.Id)
}),
Expires = DateTime.UtcNow.AddHours(2),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return new AuthenticationResult
{
Success = true,
Token = tokenHandler.WriteToken(token)
};
}
現在當我的控制器將具有授權標簽時:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class PostsController : ControllerBase
{
private readonly IPostService _postService;
public PostsController(IPostService postService)
{
_postService = postService;
}
[HttpGet(ApiRoutes.Posts.GetAll)]
public async Task<IActionResult> GetAll()
{
return Ok(await _postService.GetPostsAsync()); //returns all Posts from db
}
}
它總是拋出 401。 jwt.io 解碼后的令牌本身看起來很好:
//header
{
"alg": "HS256"
}
//payload
{
"sub": "[email protected]",
"jti": "284db32d-6cc3-4532-96cf-55d0df9c3606",
"email": "[email protected]",
"id": "e76b112a-55bd-4c4b-832b-32ee7f6b1445",
"nbf": 1641585546,
"exp": 1641592746,
"iat": 1641585546
}
//signature
HMACSHA256(
base64UrlEncode(header) "."
base64UrlEncode(payload),
your-256-bit-secret
)
我的應用設定:
"JwtSettings": {
"Secret": "sYwxnmRz6PpTnoQC7Fj3oQdqLcFtQEdI" //Im aware of not sharing this but this api is just for fun
},
"SwaggerOptions": {
"JsonRoute": "swagger/{documentName}/swagger.json",
"Description": "ShareThoughtAPI",
"UIEndpoint": "v1/swagger.json"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
我想我已經按部就班了。我一直在關注本教程并做了同樣的事情,但問題仍然存在。我確保了 Startup 類中授權、路由和身份驗證的正確順序,并且 JWT 配置基本上是復制粘貼的。我已經閱讀了 100 次代碼,但仍然找不到任何問題。我錯過了什么?
uj5u.com熱心網友回復:
這在 .NET6 中對我有用。但是,如果沒有 Audience 和 Issuer 屬性,它就無法作業。
代幣生成:
var plainTextSecurityKey = "This is secret";
var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(
Encoding.UTF8.GetBytes(plainTextSecurityKey));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey,
Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
// -------------------------
var claimsIdentity = new ClaimsIdentity(new List<Claim>()
{
new Claim(ClaimTypes.Name, "[email protected]"),
new Claim(ClaimTypes.Role, "Administrator"),
}, "Custom");
var securityTokenDescriptor = new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor()
{
Audience = "http://my.website.com",
Issuer = "http://my.tokenissuer.com",
Subject = claimsIdentity,
SigningCredentials = signingCredentials
};
var tokenHandler = new JwtSecurityTokenHandler();
var plainToken = tokenHandler.CreateToken(securityTokenDescriptor);
var signedAndEncodedToken = tokenHandler.WriteToken(plainToken);
Console.WriteLine(signedAndEncodedToken);
令牌驗證:
builder.Services
.AddAuthentication(cfg =>
{
cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
var plainTextSecurityKey = "This is secret";
var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(
Encoding.UTF8.GetBytes(plainTextSecurityKey));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey,
Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKey = signingKey
};
// this is useful as you can see the actual issue
cfg.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = async context =>
{
var ex = context.Exception;
}
};
});
請注意如何OnAuthenticationFailed附加,以便在出現問題時可以看到例外。但是請注意,實際問題可能嵌套在InnerException例外鏈的深處。
uj5u.com熱心網友回復:
我設法找到了答案。我的錯誤與我要尋找的地方相去甚遠。
我之前的 Swagger 配置如下所示:
services.AddSwaggerGen(x =>
{
x.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "ShareThoughtAPI", Version = "v1 " });
var security = new OpenApiSecurityRequirement();
x.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the bearer scheme",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
x.AddSecurityRequirement(security);
});
然而,現在作業的正確方法應該是這樣的:
services.AddSwaggerGen(x =>
{
x.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "ShareThoughtAPI", Version = "v1 " });
x.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the bearer scheme",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
x.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
}
},
new List<string>()
}
});
});
現在從 Postman 或 Fiddler 發送請求可以在 Swagger 中作業,并且配置令牌不會一直拋出 401。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/409270.html
標籤:
上一篇:如何將Web請求中的Windows身份驗證令牌傳遞給api?
下一篇:盡管使用了EC.visibility_of_element_located().click()方法,但單擊按鈕時出現SeleniumTimeoutException錯誤?
