ASP.NET Core 中基于令牌的身份验证 [英] Token Based Authentication in ASP.NET Core

查看:25
本文介绍了ASP.NET Core 中基于令牌的身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ASP.NET Core 应用程序.我正在尝试实施基于令牌的身份验证,但无法弄清楚如何为我的案例使用新的安全系统.我浏览了 examples 但他们对我帮助不大,他们正在使用cookie 身份验证或外部身份验证(GitHub、Microsoft、Twitter).

I'm working with ASP.NET Core application. I'm trying to implement Token Based Authentication but can not figure out how to use new Security System for my case. I went through examples but they didn't help me much, they are using either cookie authentication or external authentication (GitHub, Microsoft, Twitter).

我的场景是:angularjs 应用程序应该请求 /token url 传递用户名和密码.WebApi 应授权用户并返回 access_token,Angularjs 应用程序将在以下请求中使用该 access_token.

What my scenario is: angularjs application should request /token url passing username and password. WebApi should authorize user and return access_token which will be used by angularjs app in following requests.

我找到了关于在当前版本的 ASP.NET 中实现我所需要的东西的很棒的文章 - 使用 ASP.NET Web API 2、Owin 和 Identity 的基于令牌的身份验证.但是如何在 ASP.NET Core 中做同样的事情对我来说并不明显.

I've found great article about implementing exactly what I need in current version of ASP.NET - Token Based Authentication using ASP.NET Web API 2, Owin, and Identity. But it is not obvious for me how to do the same thing in ASP.NET Core.

我的问题是:如何配置 ASP.NET Core WebApi 应用程序以使用基于令牌的身份验证?

My question is: how to configure ASP.NET Core WebApi application to work with token based authentication?

推荐答案

.Net Core 3.1 更新:

David Fowler(ASP .NET Core 团队的架构师)组合了一组非常简单的任务应用程序,包括一个 演示 JWT 的简单应用.我很快就会在这篇文章中加入他的更新和简单化的风格.

Update for .Net Core 3.1:

David Fowler (architect for the ASP .NET Core team) has put together an incredibly simple set of task applications, including a simple application demonstrating JWT. I'll be incorporating his updates and simplistic style to this post soon.

此答案的先前版本使用了 RSA;如果生成令牌的相同代码也在验证令牌,则实际上没有必要.但是,如果您要分配责任,您可能仍希望使用 Microsoft.IdentityModel.Tokens.RsaSecurityKey 的实例来执行此操作.

Previous versions of this answer used RSA; it's really not necessary if your same code that is generating the tokens is also verifying the tokens. However, if you're distributing the responsibility, you probably still want to do this using an instance of Microsoft.IdentityModel.Tokens.RsaSecurityKey.

  1. 创建一些我们稍后会用到的常量;这是我所做的:

  1. Create a few constants that we'll be using later; here's what I did:

const string TokenAudience = "Myself";
const string TokenIssuer = "MyProject";

  • 将此添加到您的 Startup.cs 的 ConfigureServices.稍后我们将使用依赖注入来访问这些设置.我假设你的 authenticationConfiguration 是一个 ConfigurationSectionConfiguration 对象,这样你就可以有不同的调试和生产配置.确保您安全地存放您的密钥!它可以是任何字符串.

  • Add this to your Startup.cs's ConfigureServices. We'll use dependency injection later to access these settings. I'm assuming that your authenticationConfiguration is a ConfigurationSection or Configuration object such that you can have a different config for debug and production. Make sure you store your key securely! It can be any string.

    var keySecret = authenticationConfiguration["JwtSigningKey"];
    var symmetricKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keySecret));
    
    services.AddTransient(_ => new JwtSignInHandler(symmetricKey));
    
    services.AddAuthentication(options =>
    {
        // This causes the default authentication scheme to be JWT.
        // Without this, the Authorization header is not checked and
        // you'll get no results. However, this also means that if
        // you're already using cookies in your app, they won't be 
        // checked by default.
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    })
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters.ValidateIssuerSigningKey = true;
            options.TokenValidationParameters.IssuerSigningKey = symmetricKey;
            options.TokenValidationParameters.ValidAudience = JwtSignInHandler.TokenAudience;
            options.TokenValidationParameters.ValidIssuer = JwtSignInHandler.TokenIssuer;
        });
    

    我已经看到其他答案更改了其他设置,例如 ClockSkew;默认设置使其适用于时钟不完全同步的分布式环境.这些是您需要更改的唯一设置.

    I've seen other answers change other settings, such as ClockSkew; the defaults are set such that it should work for distributed environments whose clocks aren't exactly in sync. These are the only settings you need to change.

    设置身份验证.您应该在任何需要您的 User 信息的中间件之前添加这一行,例如 app.UseMvc().

    Set up Authentication. You should have this line before any middleware that requires your User info, such as app.UseMvc().

    app.UseAuthentication();
    

    请注意,这不会导致您的令牌与 SignInManager 或其他任何东西一起发出.您需要提供自己的 JWT 输出机制 - 见下文.

    Note that this will not cause your token to be emitted with the SignInManager or anything else. You will need to provide your own mechanism for outputting your JWT - see below.

    您可能想要指定一个 AuthorizationPolicy.这将允许您使用 [Authorize("Bearer")] 指定仅允许 Bearer 令牌作为身份验证的控制器和操作.

    You may want to specify an AuthorizationPolicy. This will allow you to specify controllers and actions that only allow Bearer tokens as authentication using [Authorize("Bearer")].

    services.AddAuthorization(auth =>
    {
        auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
            .AddAuthenticationTypes(JwtBearerDefaults.AuthenticationType)
            .RequireAuthenticatedUser().Build());
    });
    

  • 棘手的部分来了:构建令牌.

  • Here comes the tricky part: building the token.

    class JwtSignInHandler
    {
        public const string TokenAudience = "Myself";
        public const string TokenIssuer = "MyProject";
        private readonly SymmetricSecurityKey key;
    
        public JwtSignInHandler(SymmetricSecurityKey symmetricKey)
        {
            this.key = symmetricKey;
        }
    
        public string BuildJwt(ClaimsPrincipal principal)
        {
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
            var token = new JwtSecurityToken(
                issuer: TokenIssuer,
                audience: TokenAudience,
                claims: principal.Claims,
                expires: DateTime.Now.AddMinutes(20),
                signingCredentials: creds
            );
    
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
    

    然后,在您想要令牌的控制器中,如下所示:

    Then, in your controller where you want your token, something like the following:

    [HttpPost]
    public string AnonymousSignIn([FromServices] JwtSignInHandler tokenFactory)
    {
        var principal = new System.Security.Claims.ClaimsPrincipal(new[]
        {
            new System.Security.Claims.ClaimsIdentity(new[]
            {
                new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, "Demo User")
            })
        });
        return tokenFactory.BuildJwt(principal);
    }
    

    这里,我假设您已经有一个校长.如果您使用的是 Identity,则可以使用 IUserClaimsPrincipalFactory<> 将您的 User 转换为 ClaimsPrincipal.

    Here, I'm assuming you already have a principal. If you are using Identity, you can use IUserClaimsPrincipalFactory<> to transform your User into a ClaimsPrincipal.

    测试:获取令牌,将其放入 jwt.io 的表单中.我上面提供的说明还允许您使用配置中的秘密来验证签名!

    To test it: Get a token, put it into the form at jwt.io. The instructions I provided above also allow you to use the secret from your config to validate the signature!

    如果您结合 .Net 4.5 中的仅承载身份验证在 HTML 页面的部分视图中呈现此内容,您现在可以使用 ViewComponent 来执行相同的操作.它与上面的控制器操作代码大致相同.

    If you were rendering this in a partial view on your HTML page in combination with the bearer-only authentication in .Net 4.5, you can now use a ViewComponent to do the same. It's mostly the same as the Controller Action code above.

    这篇关于ASP.NET Core 中基于令牌的身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆