背景:
我正在尝试支持授权代码流,以便从我的应用程序启用SSO到第三方应用程序。
现在我停留在Unprotect方法的实现上,该方法应该返回AuthenticationTicket。
OAuth2服务器配置:
var allowInsecureHttp = bool.Parse(ConfigurationManager.AppSettings["AllowInsecureHttp"]);
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = allowInsecureHttp,
TokenEndpointPath = new PathString("/oauth2/token"),
AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(HlGlobals.Kernel),
AccessTokenFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel),
AuthorizationCodeProvider = new SimpleAuthenticationTokenProvider(),
AuthorizationCodeFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel)
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
JWT令牌生成/保护方法:
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
// Get the client and assign to GUID -- the audience is api this token will be valid against
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
Guid clientId;
bool isValidAudience = Guid.TryParse(audienceId, out clientId);
// Check for a valid Client Guid in the Auth ticket properties
if (!isValidAudience)
{
throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");
}
// Create the JWT token
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
// Return the JWT Token
return jwt;
}
最后,'取消保护'负责验证JWT以及返回和认证票证的方法:
public AuthenticationTicket Unprotect(string protectedText)
{
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
Guid clientId;
bool isValidAudience = Guid.TryParse(audienceId, out clientId);
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var tokenValidationParameters = new TokenValidationParameters
{
ValidAudience = audienceId,
ValidIssuer = _issuer,
IssuerSigningKey = signingKey // Cannot convert HMAC Signing Credentials to System.IdentityModel.Tokens.SecurityKey
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true,
RequireSignedTokens = true,
RequireExpirationTime = true,
ValidateIssuerSigningKey = true
};
var handler = new JwtSecurityTokenHandler();
SecurityToken token = null;
var principal = handler.ValidateToken(protectedText, tokenValidationParameters, out token);
var identity = principal.Identities;
return new AuthenticationTicket(identity.First(), new AuthenticationProperties());
}
跳转的一个问题是发行人签名密钥。我无法想出一个可接受的参数。我看到了错误消息:
无法将HMAC签名凭据转换为 System.IdentityModel.Tokens.SecurityKey
说实话,我不确定为什么Protect方法需要触发。我认为流程将以JWT令牌的返回结束,但显然不是。现在我正在努力实施Unprotect方法,因为这是我以前从未与之斗争过的事情。
即使我将所有选项设置为' false'在tokenValidationParamters上我仍然在验证时收到以下错误:
类型的例外 ' System.IdentityModel.SignatureVerificationFailedException'发生了 在System.IdentityModel.Tokens.Jwt.dll中但未在用户中处理 代码
其他信息:IDX10503:签名验证失败。按键 尝试过:''。
遇到异常:
''
令牌: ' {"典型值":" JWT"" ALG":" HS256"} {" ISS&#34 ;:" http://myissuer.com"" AUD":" 346e886acabf457cb9f721f615ff996c""&EXP#34;:1510925372," NBF& #34;:1510925072}'
当我使用JWT.IO将值与解密令牌进行比较时,所有值都按预期匹配。
关于我在这里做错了什么的指导,或者如何在tokenvalidationparamters上使用有效的签名密钥调用validateToken将是最有帮助和最理解的。
提前致谢!
修改
我很好奇为什么Unprotect正在解雇...我以为我应该将JWT令牌返回给客户端。在Unprotect方法和JWT之前返回JWT的方法永远不会返回给客户端。
我是否配置错误?
答案 0 :(得分:1)
在Startup.cs文件中,调用以下方法。当用户实际尝试登录到身份验证服务器端点时,将调用customJwtFormat中的Protect方法。当用户尝试通过“ Bearer [token]”身份验证模型访问受保护的api URL时,将调用unprotect方法。如果您没有在Startup.cs文件中说例如 app.UseOAuthBearerAuthentication ,您最终将得到诸如
之类的错误。Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware 警告:0:收到无效的承载令牌
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
AccessTokenFormat = _tokenFormat
});
按如下所示创建customjwtFormat,您可以根据需要更改实现。
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
//var signingKey = new HmacSigningCredentials(keyByteArray);
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(keyByteArray);
securityKey.KeyId = ConfigurationManager.AppSettings["as:AudienceId"];
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string authority = ConfigurationManager.AppSettings["Authority"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(keyByteArray);
var tokenValidationParameters = new TokenValidationParameters
{
ValidAudience = audienceId,
ValidIssuer = _issuer,
IssuerSigningKey = signingKey,
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true,
RequireSignedTokens = true,
RequireExpirationTime = true,
ValidateIssuerSigningKey = true
};
var handler = new JwtSecurityTokenHandler();
SecurityToken token = null;
// Unpack token
var pt = handler.ReadJwtToken(protectedText);
string t = pt.RawData;
var principal = handler.ValidateToken(t, tokenValidationParameters, out token);
var identity = principal.Identities;
return new AuthenticationTicket(identity.First(), new AuthenticationProperties());
}
答案 1 :(得分:0)
你应该使用这样的东西
public AuthenticationTicket Unprotect(string protectedText)
{
if (string.IsNullOrWhiteSpace(protectedText))
{
throw new ArgumentNullException("protectedText");
}
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(protectedText);
SecurityToken validatedToken;
string t = ((JwtSecurityToken)token).RawData;
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
//var signingKey = new HmacSigningCredentials(keyByteArray);
var validationParams = new TokenValidationParameters()
{
ValidateLifetime = false,
ValidAudience = audienceId,
ValidIssuer = audienceId,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningToken = new BinarySecretSecurityToken(keyByteArray)
};
var principal = handler.ValidateToken(t, validationParams, out validatedToken);
var identity = principal.Identities;
return new AuthenticationTicket(identity.First(), new AuthenticationProperties());
}