9

在这种情况下,我让用户登录(MVC 5)Web 应用程序,然后该应用程序充当代理以登录(Web API 2)API(使用基于 SSL 的基本)并返回承载/访问令牌。我正在使用 Thinktecture.IdentityModel.Client.OAuth2Client 处理登录并获取访问令牌,一切正常。

发生了一些其他事情,但现在我希望 Web 应用程序能够解码访问令牌以访问 API 上设置的声明(特别是登录 API 后返回的用户 ID)。

我正在使用经过大量演示的UseOAuthAuthorizationServer扩展UseOAuthBearerAuthentication方法,其令牌端点几乎是开箱即用的,但可以自定义OAuthAuthorizationServerOptions.Provider访问我自己的存储库。

我在两个应用程序上都有相同的 MachineKey,但我不清楚如何解码令牌,尽管我知道我可能不得不使用该SecureDataFormat.Unprotect方法。

我在 Web 应用程序中最接近的尝试是:

Task<TokenResponse> response = client.RequestResourceOwnerPasswordAsync(model.Email, model.Password);

IDataProtector dataProtecter = Startup.DataProtectionProvider.Create("does this matter?");
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtecter);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(response.Result.AccessToken);

使用 Startup.DataProtectionProvider 设置如下:

public partial class Startup
{
    internal static IDataProtectionProvider DataProtectionProvider { get; private set; }

    public void Configuration(IAppBuilder app)
    {
        DataProtectionProvider = app.GetDataProtectionProvider();
        this.ConfigureAuth(app);
    }
}

我的后备计划是提供一种 API 方法,该方法在登录后返回我感兴趣的信息,但看起来似乎太过分了,因为它构成了令牌中声明的一部分(据我所知)。

我试图围绕 JWT(我查看过 Thinktecture、Microsoft 源代码和其他各种论坛)展开思考,但不确定这是否会有所帮助(尽管以纯文本形式提供的声明对我们很有用)。我还没有找到一个允许使用基本身份验证登录并返回包含访问令牌的自定义 JWT 的示例。

无论如何,我希望那是足够的信息和任何帮助将不胜感激......干杯

4

2 回答 2

4

你们已经很亲近了。沙迪走在了正确的轨道上。即使这是一个单独的 mvc 应用程序,您仍然需要如图所示解密令牌并提取声明。如果您的 Web api 令牌位于名为 accessToken 的变量中,您可以在您的 mvc Web 应用程序中执行以下操作。(注意mvc同时使用了承载认证和cookie认证,OAuthBearerOptions是一个静态类)

//Unprotect the token 
var unencryptedToken = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(accessToken);
//Extract the claims identity from the token
var identity = unencryptedToken.Identity;

//Once you have the claims identity extracted, create a new claims identity that uses 
//ApplicationCookie as the default authentication type

var id = new ClaimsIdentity(identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);

// Now you are ready to sign in with your new claims identity. You basically created an  
//application cookie from a bearer token and now using this cookie to sign-in

AuthenticationManager.SignIn(id);

这是您的 startup.auth.cs 应该包含的方式(请注意,我们有一个 OAuthBearerAuthenticationOptions 静态成员,我们调用 app.UseOAuthBearerAuthentication() 只是为了能够解密承载令牌

public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

    static Startup()
    {
        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
    }


    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
    }
于 2014-12-29T22:11:24.327 回答
1

如果您使用的是 UseOAuthBearerAuthentication,您可以在 Startup.Auth.cs 类上将 OAuthBearerOptions 设为静态:

public partial class Startup
{
    public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
    ...

    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per    request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        ...

    }
}

现在,您可以从代码中的任何位置以这种方式取消对收到的令牌的保护:

var ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(response.Result.AccessToken);

现在您可以使用票证访问 API 用户的声明:

ticket.Identity.Claims

希望这能回答你的问题。

编辑

SO上的这个答案将解决您的问题,请看一下。

于 2014-10-26T13:34:39.870 回答