好吧,我想我想通了。有两种方法。一个简单直接的方法是使用IssuerSigningKeys属性(我怎么不能在第一时间发现它)。代码如下所示:
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKeys = new List<RsaSecurityKey>
{
Utils.GetSigningKey(isPrimary: true),
Utils.GetSigningKey(isPrimary: false)
},
},
});
第二种方法是自定义IOAuthBearerAuthenticationProvider。该代码看起来是这样的:首先,
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = new string[] { "*" },
IssuerSecurityTokenProviders = new List<IIssuerSecurityTokenProvider>()
{
// Dummy object which won't be used anywhere. It is used to work around parameter validation error about no token provider specified.
new SymmetricKeyIssuerSecurityTokenProvider("dummy", "dummy")
},
// This is where validation work happens.
Provider = new BearerAuthenticationProvider(app)
});
然后,BearerAuthenticationProvider类:
/// <summary>
/// Bearer authentication provider.
/// </summary>
public class BearerAuthenticationProvider : IOAuthBearerAuthenticationProvider
{
/// <summary>
/// App config.
/// </summary>
private readonly IAppBuilder appConfig;
/// <summary>
/// Handles applying the authentication challenge to the response message.
/// </summary>
public Func<OAuthChallengeContext, Task> OnApplyChallenge { get; set; }
/// <summary>
/// Handles processing OAuth bearer token.
/// </summary>
public Func<OAuthRequestTokenContext, Task> OnRequestToken { get; set; }
/// <summary>
/// Handles validating the identity produced from an OAuth bearer token.
/// </summary>
public Func<OAuthValidateIdentityContext, Task> OnValidateIdentity { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="T:Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationProvider" /> class
/// </summary>
public BearerAuthenticationProvider(IAppBuilder appConfig)
{
this.appConfig = appConfig;
this.OnRequestToken = (OAuthRequestTokenContext context) =>
{
var idContext = new OAuthValidateIdentityContext(context.OwinContext, null, null);
this.ValidateIdentity(idContext);
return Task.FromResult<int>(0);
};
this.OnValidateIdentity = (OAuthValidateIdentityContext context) => Task.FromResult<object>(null);
this.OnApplyChallenge = (OAuthChallengeContext context) => Task.FromResult<object>(null);
}
/// <summary>
/// Handles applying the authentication challenge to the response message.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public Task ApplyChallenge(OAuthChallengeContext context)
{
return this.OnApplyChallenge(context);
}
/// <summary>
/// Handles processing OAuth bearer token.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public virtual Task RequestToken(OAuthRequestTokenContext context)
{
return this.OnRequestToken(context);
}
/// <summary>
/// Handles validating the identity produced from an OAuth bearer token.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public virtual Task ValidateIdentity(OAuthValidateIdentityContext context)
{
const string AuthHeaderName = "Authorization";
if (context.Request.Headers.ContainsKey(AuthHeaderName))
{
var jwt = context.Request.Headers[AuthHeaderName].Replace("Bearer ", string.Empty);
var token = new JwtSecurityToken(jwt);
var claimIdentity = new ClaimsIdentity(token.Claims, "ExternalBearer");
var param = new TokenValidationParameters()
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKeys = new List<RsaSecurityKey>
{
Utils.GetSigningKey(isPrimary: true),
Utils.GetSigningKey(isPrimary: false)
},
};
SecurityToken securityToken = null;
var handler = new JwtSecurityTokenHandler();
var identity = handler.ValidateToken(token.RawData, param, out securityToken);
var claimPrincipal = new ClaimsPrincipal(claimIdentity);
context.Response.Context.Authentication.User = claimPrincipal;
context.Validated(claimIdentity);
}
else
{
throw new Exception("Invalid authorization header.");
}
return this.OnValidateIdentity(context);
}
}
第一种方法初始化在应用程序启动,只有做出改变路两个签名密钥,当进程重新启动。第二种方法在运行时检索密钥,因此密钥翻转不需要重新启动服务。