ASP.NET Identity 2.0 针对我们自己的承载服务器进行身份验证

ASP.NET Identity 2.0 Authenticate against our own bearer server

全部,

我有一个安全服务器,其唯一目的是从单个端点提供不记名令牌:http://example.com/token

请求示例:

POST http://example.com/token HTTP/1.1
User-Agent: Fiddler
Content-Type: x-www-form-urlencoded
Host: example.com
Content-Length: 73

grant_type=password&username=example@example.com&password=examplePassword

响应示例:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 16 Aug 2016 12:04:39 GMT
{
  "access_token": "xxxx",
  "token_type": "bearer",
  "expires_in": 17999,
  "refresh_token": "xxxx",
  ".issued": "Tue, 16 Aug 2016 12:04:38 GMT",
  ".expires": "Tue, 16 Aug 2016 17:04:38 GMT"
}

我们有一个 angular 应用程序使用此端点进行身份验证,并且做得很好。

我们正在尝试创建一个使用同一服务器进行身份验证的 MVC 应用程序但没有取得太大成功,如果可能的话,我们希望代码位于 Identity 2.0 之上。

在我们的 AccountController(示例项目)中,我们有处理登录的 Login(LoginModel model) 方法,看起来像这样(与示例项目模板相同):

var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

我们有自己的 IUserStore、UserManager、SignInManager 实现。

我考虑过覆盖

public Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout) on `SignInManager<,>` and make a web call across to the security server.

PasswordSignInAsync 的默认实现调用 UserManager.FindByNameAsync 但这意味着我必须在我的安全服务器上公开一个查找方法来确认用户名是否存在,这听起来确实不太好。

我一定是遗漏了什么,我知道它不会这么复杂,我们的 MVC 应用程序需要使用 cookie 身份验证,但也需要维护 bear 令牌以便后续调用我们的其他资源服务器。

(我很感激我可能在这里混淆了技术,因此出现了这个问题)。

这也是 OWIN 上的 运行。

在这种情况下,我认为您不应该在 MVC 应用程序中使用 Identity 2.0。你应该创建一个 AuthenticationClient 来调用你的身份验证服务器,你也可以使用这个库来构建这样一个客户端 https://www.nuget.org/packages/Thinktecture.IdentityModel.Client/

public class AuthenticationClient {
    public ClaimsIdentity GetClaimsIdentity(string username, string password) {
         //Call your authentication server to get your token and also claims associated with your identity.
         //You can look at an example code how to do it: https://github.com/IdentityServer/IdentityServer3.Samples/blob/master/source/Clients/ConsoleResourceOwnerClient/Program.cs
         //and create a ClaimsIdentity object out of those information

         var identity = GetIdentity();

         //The key point here is to add AccessToken and RefreshToken as custom claims to your identity so you retrieve these tokens back on subsequent requests.
        identity.AddClaim(new Claim("access_token", accessToken));
        identity.AddClaim(new Claim("refresh_token", refreshToken));
    }
}

这将满足您的要求:

Use cookie authentication but also maintain the bear token for subsequent calls to our other resource server.

你在 AccountController 上的 Login 方法应该是这样的:

public ActionResult Login(LoginModel model)
{
     var identity = authenticationClient.GetClaimsIdentity(model.UserName, model.Password);

     if (identity == null) {
         return new HttpUnauthorizedResult();
     }
     //Sign in the user
     var ctx = Request.GetOwinContext();
     var authenticationManager = ctx.Authentication;
     authenticationManager.SignIn(identity);

     return new HttpStatusCodeResult(HttpStatusCode.OK);
}

我假设你已经注册了这个中间件来使用 Cookie 认证:

public void ConfigureAuth(IAppBuilder app)
{
   app.UseCookieAuthentication(new CookieAuthenticationOptions
   {
      AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
      LoginPath = new PathString("/Account/Login")
   });
}

现在对于所有后续请求,您可以取回访问令牌以从您的 ClaimsIdentity 调用您的资源服务器:

User.Identity.Claims.FirstOrDefault(x => x.Type == "access_token");