实施 Identity 2.1 + OWIN OAuth JWT 不记名令牌时如何从 Web API 控制器端点进行身份验证

Posted

技术标签:

【中文标题】实施 Identity 2.1 + OWIN OAuth JWT 不记名令牌时如何从 Web API 控制器端点进行身份验证【英文标题】:How to authenticate from Web API controller endpoint when implementing Identity 2.1 + OWIN OAuth JWT bearer token 【发布时间】:2016-01-09 02:57:04 【问题描述】:

我无法在我的控制器方法中进行身份验证,这是我的确认用户注册工作流程的一部分,我正在寻找一些指导来证明我的实施是正确的。

我的控制器方法有以下代码;我已经确认用户已被填充(作为FindById 调用的一部分)但在SignIn 之后; this.Authentication.User.Identity 未设置(Name 为空白,IsAuthenticated 为假):

this.Authentication.SignOut("JWT");

ApplicationUser user = await this.AppUserManager.FindByIdAsync(userId);

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(this.AppUserManager, "JWT");

this.Authentication.SignIn(new AuthenticationProperties()  IsPersistent = true , oAuthIdentity);

这是在使用 OWIN OAuth 时自动登录的正确方法吗?

完整的控制器方法可以在这里看到: https://gist.github.com/chrismoutray/8a8e5f6a7b433571613b

作为参考,我一直在关注名为 Bit of Tech 的博客中的一组文章,这些文章允许我使用 JWT 不记名令牌设置 OWIN OAuth。

第 3 部分特别讨论了 JWT(共 5 个):http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/

从我创建自定义 OAuth 提供程序的文章中,该提供程序继承自 OAuthAuthorizationServerProvider 并实现 GrantResourceOwnerCredentials,当我的客户端代码 (AngularJS) 尝试使用端点 /oauth/token 进行身份验证时,我可以看到它提供然后可以访问正确的响应和受保护的端点(使用授权属性)。

所以通过中间件进行身份验证确实有效,但从控制器方法内部进行身份验证的正确方法是什么?

【问题讨论】:

克里斯,我不清楚你为什么要实现 OAuthProvider。你是发行代币还是消费? @BrentSchmaltz - 我考虑了我的方法并从不同的角度解决了这个问题。所以现在,不要尝试使用 Authentication.SignIn(..) 从控制器方法内部登录。我创建了一个临时的一次性密码(令牌),客户端应用程序将使用该密码首次对用户进行身份验证。 【参考方案1】:

我想我会分享我想出的解决方案。

简短的回答;我创建了一个临时的一次性密码(令牌),用于首次验证用户身份

这里的要点供参考: https://gist.github.com/chrismoutray/159e6fd74f45d88efd12

到摘要 - 在AccountController ConfirmSignUp 方法中;我使用用户管理器生成一个自定义令牌,我称之为GRANT-ACCESS,然后使用 uri 中的用户名和令牌重定向到我的confirm-signup 页面。 我的 Angular 应用程序将 ui-route 解析为 confirm-signup 并执行登录,将令牌作为密码传递。

var tokenResult = this.AppUserManager.GenerateUserTokenAsync("GRANT-ACCESS", userId);
string token = tokenResult.Result;

Uri redirectLocation = new Uri(
    string.Format("http://localhost:45258/#/confirm-signup?user=0&token=1", 
    Uri.EscapeDataString(user.UserName), Uri.EscapeDataString(token)));

return Redirect(redirectLocation);

最后对GrantResourceOwnerCredentials 进行了修改,如果FindAsync(通过用户名和密码)没有返回用户,那么我再试一次,但这次将context.Password 视为GRANT-ACCESS 用户要验证的令牌。如果令牌有效,那么我会返回 JWT 身份验证票,就像用户使用有效密码登录一样。

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)

    ... code obmitted

    ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

    if (user == null)
    
        user = await userManager.FindByNameAsync(context.UserName);

        ... null checks obmitted

        string token = context.Password;
        bool result = await userManager.VerifyUserTokenAsync(user.Id, "GRANT-ACCESS", token);
    

    ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");

    var ticket = new AuthenticationTicket(oAuthIdentity, null);

    context.Validated(ticket);

【讨论】:

以上是关于实施 Identity 2.1 + OWIN OAuth JWT 不记名令牌时如何从 Web API 控制器端点进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

没有 OWIN 和 AspNet.Identity 的基于 Asp.Net Web Api 令牌的授权

ASP.NET (OWIN) Identity:如何从 Web API 控制器获取 UserID?

Identity Owin 是不是需要延迟加载?

MVC Owin Identity 2 CheckPasswordAsync() 不会执行

ASP.NET Identity 2.0 解密 Owin cookie

MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN