如何实现ISecureDataFormat <authenticationticket> Unprotect方法?

时间:2017-11-17 13:28:02

标签: c# asp.net-web-api oauth-2.0 jwt

背景:

我正在尝试支持授权代码流,以便从我的应用程序启用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;
}

最后,&#39;取消保护&#39;负责验证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方法,因为这是我以前从未与之斗争过的事情。

即使我将所有选项设置为&#39; false&#39;在tokenValidationParamters上我仍然在验证时收到以下错误:

  

类型的例外   &#39; System.IdentityModel.SignatureVerificationFailedException&#39;发生了   在System.IdentityModel.Tokens.Jwt.dll中但未在用户中处理   代码

     

其他信息:IDX10503:签名验证失败。按键   尝试过:&#39;&#39;。

     

遇到异常:

     

&#39;&#39;

     

令牌:   &#39; {&#34;典型值&#34;:&#34; JWT&#34;&#34; ALG&#34;:&#34; HS256&#34;} {&#34; ISS&#34 ;:&#34; http://myissuer.com&#34;&#34; AUD&#34;:&#34; 346e886acabf457cb9f721f615ff996c&#34;&#34;&EXP#34;:1510925372,&#34; NBF& #34;:1510925072}&#39;

当我使用JWT.IO将值与解密令牌进行比较时,所有值都按预期匹配。

关于我在这里做错了什么的指导,或者如何在tokenvalidationparamters上使用有效的签名密钥调用validateToken将是最有帮助和最理解的。

提前致谢!

修改

我很好奇为什么Unprotect正在解雇...我以为我应该将JWT令牌返回给客户端。在Unprotect方法和JWT之前返回JWT的方法永远不会返回给客户端。

我是否配置错误?

2 个答案:

答案 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());

    }