我在.net核心中编写了一个使用API和网站的网络应用程序。
Web服务构建JWT令牌。 这是服务配置(删除不必要的部分)
foo
到目前为止,这么好。登录有效,我的网站端授权有效,我可以使用foo
属性。
问题是,我已登录网站,但未登录API。
我不能将public void ConfigureServices(IServiceCollection services)
{
//...
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "ExampleIssuer",
// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "ExampleAudience",
// Validate the token expiry
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero,
};
var serialiser = services.BuildServiceProvider().GetService<IDataSerializer<AuthenticationTicket>>();
var dataProtector = services.BuildServiceProvider().GetDataProtector(new string[] {$"IronSphere.Web.Site-Auth"});
services
.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = tokenValidationParameters;
})
.AddCookie(cookie =>
{
cookie.Cookie.Name = "access_token";
cookie.TicketDataFormat = new JwtTokenValidator(
SecurityAlgorithms.HmacSha256,
tokenValidationParameters, serialiser, dataProtector);
});
//...
}
- 属性用于我的API方法(是的,当然,这是有意义的。)
因此,当我登录时,每次调用API时,我也会在标头中发送令牌(这样,我可以在API控制器中读取它)。我想我需要反序列化它。
我尝试使用依赖注入将[Authorize]
放入我的控制器中:
[Authorize]
然后从标题中取出密钥,反序列化,并且我的用户对象包含声明。但是,当我尝试注入任何控制器时,它会使我的应用程序崩溃(只是一条消息,即dotnet停止工作)
任何想法如何在api被调用时验证用户? (如果你需要,我可以发布更多代码,只是不想填写太多代码)
答案 0 :(得分:1)
所以@Tseng在输入后给了我很多帮助,这是我的结果(关于如何做得更好的更多输入会很好):
在添加Startup.cs
时添加了令牌的非保护器作为服务services.AddTransient<IJwtTokenService, JwtTokenService>();
IJwtTokenService
public interface IJwtTokenService
{
string UnprotectToken(string protectedText);
}
已实施的JwtTokenService
:
public class JwtTokenService:IJwtTokenService
{
private readonly IDataSerializer<AuthenticationTicket> _ticketSerializer;
private readonly IDataProtector _dataProtector;
public JwtTokenService(IDataSerializer<AuthenticationTicket> serializer, IDataProtector protector)
{
_ticketSerializer = serializer;
_dataProtector = protector;
}
public string UnprotectToken(string protectedText)
{
SecurityKey signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(" ......... "));
TokenValidationParameters tokenValidationParameters =
_getTokenValidationParameters();
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
AuthenticationTicket authTicket;
string embeddedJwt;
try
{
// logic to deserialize token
// logic to validate token
// more logic... (algorithm,..)
}
catch (Exception)
{
return null;
}
return embeddedJwt;
}
}
所以在服务中我还必须添加IDataProtector
。之前它抛出了一个例外。
services.AddTransient(x => x.GetDataProtector(new[] {$"auth"}));
然后我可以将IJwtTokenService
添加到构造函数中以进行依赖注入,取消保护它并使用标头发送它:
protected ServiceBase(
IHttpContextAccessor contextAccessor,
IJwtTokenService jwtTokenService,
IMemoryCache memoryCache = null)
{
MemoryCache = memoryCache ?? new MemoryCache(new MemoryCacheOptions());
CachingFunctionalty = new CachingFunctionality();
HttpContextAccessor = contextAccessor;
JwtTokenService = jwtTokenService;
}
protected RestClient CreateClient()
{
RestClient restClient = new RestClient(ServiceAdress);
var token = HttpContextAccessor.HttpContext.Request.Cookies["access_token"];
if (string.IsNullOrWhiteSpace(token)) return restClient;
var unprotected = JwtTokenService.UnprotectToken(token);
restClient.AuthenticationHeaderValue = new AuthenticationHeaderValue("Bearer", unprotected);
return restClient;
}
现在我的API与AuthorizeAttribute