剖析 ASP.NET 用于 OAuth 承载身份验证的 MVC 身份

Dissecting ASP.NET MVC Identity for OAuth Bearer Authentication

我正在学习如何使用 Asp.Net MVC Identity 2.0。

我有适用于 OAuth Bearer 的代码

    [HttpGet]
    [ActionName("Authenticate")]
    [AllowAnonymous]
    public String Authenticate(string user, string password)
    {
        if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password))
        {
            return "Failed";
        }

        var userIdentity = UserManager.FindAsync(user, password).Result;
        if (userIdentity != null)
        {
            if (User.Identity.IsAuthenticated)
            {
                return "Already authenticated!";
            }

            var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
            identity.AddClaim(new Claim(ClaimTypes.Name, user));
            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userIdentity.Id));

            AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
            var currentUtc = new SystemClock().UtcNow;
            ticket.Properties.IssuedUtc = currentUtc;
            ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(1));

            string AccessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
            return AccessToken;
        }
        return "Failed in the end";
    }

这是 Startup.Auth.cs

的代码
    //This will used the HTTP header Authorization: "Bearer 1234123412341234asdfasdfasdfasdf"
    OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
    app.UseOAuthBearerAuthentication(OAuthBearerOptions);

我查看了 ClaimsIdentity 和 AuthenticationTicket 的源代码,但没有看到票证是如何为身份注册的。

我的问题是这张票是如何在 Owin 管道中注册的?

我的目标是尽可能撤销这张票。

提前致谢。

首先,这是 Taiseer Joudeh 的 great tutorial on ASP.NET Identity 2

这是将 Bearer 令牌处理添加到 OWIN 应用程序管道的行。

app.UseOAuthBearerAuthentication(OAuthBearerOptions);

另外,授权提供者是你自己写的吗?我的启动代码看起来更像这样:

app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

PublicClientId = "self";
OAuthServerOptions = new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,
    TokenEndpointPath = new PathString("/Token"),
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(1440),     //TODO: change to smaller value in production, 15 minutes maybe
    Provider = new SimpleAuthorizationServerProvider(PublicClientId),
    RefreshTokenProvider = new SimpleRefreshTokenProvider()
};

app.UseOAuthAuthorizationServer(OAuthServerOptions);

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

我的 SimpleAuthorizationServerProvider 然后有一个像这样的授权方法:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin") ?? "*";

    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

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

    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    }

    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
    identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
    identity.AddClaim(new Claim("sub", context.UserName));

    foreach (var role in userManager.GetRoles(user.Id))
    {
        identity.AddClaim(new Claim(ClaimTypes.Role, role));
    }

    var props = new AuthenticationProperties(new Dictionary<string, string>
    {
        {"as:client_id", context.ClientId ?? string.Empty}
    });

    var ticket = new AuthenticationTicket(identity, props);
    context.Validated(ticket);
}

几乎所有这些都是基于上述教程。希望对你有帮助。

更新 根据 Taiseer on this page.

,没有标准的方法来撤销令牌

Revoking access from authenticated users: Once the user obtains long lived access token he’ll be able to access the server resources as long as his access token is not expired, there is no standard way to revoke access tokens unless the Authorization Server implements custom logic which forces you to store generated access token in database and do database checks with each request. But with refresh tokens, a system admin can revoke access by simply deleting the refresh token identifier from the database so once the system requests new access token using the deleted refresh token, the Authorization Server will reject this request because the refresh token is no longer available (we’ll come into this with more details).

但是,here is an interesting approach 这可能会完成您所需要的。它只需要一些自定义实现。