c# - 如何实现 ISecureDataFormat<AuthenticationTicket> Unprotect 方法?

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

背景:

我正在尝试支持授权代码流以启用从我的应用程序到第三方应用程序的 SSO。

现在我卡在了应该返回 AuthenticationTicket 的 Unprotect 方法的实现上。

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 token 生成/保护方法:

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;
}

最后,'Unprotect' 方法负责验证 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());
}

立即发布的一个问题是发行者签名 key 。我无法提出可接受的参数。我看到错误消息:

Cannot convert HMAC Signing Credentials to System.IdentityModel.Tokens.SecurityKey

老实说,我不确定为什么 Protect 方法需要触发。我认为流程会随着 JWT token 的返回而结束,但显然不是。现在我正在努力实现 Unprotect 方法,因为这是我以前从未遇到过的事情。

即使我在 tokenValidationParamters 上将所有选项都设置为“false”,我仍然会在验证时收到以下错误:

An exception of type 'System.IdentityModel.SignatureVerificationFailedException' occurred in System.IdentityModel.Tokens.Jwt.dll but was not handled in user code

Additional information: IDX10503: Signature validation failed. Keys tried: ''.

Exceptions caught:

''.

token: '{"typ":"JWT","alg":"HS256"}.{"iss":"http://myissuer.com","aud":"346e886acabf457cb9f721f615ff996c","exp":1510925372,"nbf":1510925072}'

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

任何关于我在这里可能做错了什么的指导,或者如何使用 token 验证参数上的有效签名 key 调用 validateToken 的任何指导都将非常有帮助和赞赏。

提前致谢!

编辑:

我很好奇为什么 Unprotect 会触发……我想我应该向客户端返回一个 JWT token 。返回 JWT 的方法在 Unprotect 方法之前触发,并且 JWT 永远不会返回给客户端。

我是否配置不正确?

最佳答案

在您的 Startup.cs 文件中调用以下方法。当用户实际尝试登录身份验证服务器端点时,将调用 customJwtFormat 中的 Protect 方法。当用户尝试通过“Bearer [token]”身份验证模型访问 protected api url 时,将调用 unprotect 方法。例如,如果您不在 Startup.cs 文件中说明 app.UseOAuthBearerAuthentication,您最终会收到诸如

之类的错误

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Warning: 0 : invalid bearer token received

 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());
    }

关于c# - 如何实现 ISecureDataFormat<AuthenticationTicket> Unprotect 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47351750/

相关文章:

c# - 从 .NET 通过电子邮件地址搜索 AD 用户的正确方法

asp.net - Azure Web App - 限制对 API 管理的访问

Django OAuth2错误: invalid_client and client_id=None when client_id has been provided

c# - 'Microsoft.ACE.OLEDB.14.0' 提供者未在本地机器上注册

C# Gridview 第一行数据不返回

c# - 将 Web API Controller 添加到不同的程序集

c# - MVC 中的 OAuth 2.0 Mailkit "Authentication failed",但 C# 控制台应用程序工作正常

android - Google API 对来自 GoogleAuthUtil.getToken 的一次性授权代码的授予无效

c# - 发布没有配置文件的版本

c# - AngularJs/webAPI : recieving null in the parameter of webAPI