.NET Core 2.0 上的 JWT [英] JWT on .NET Core 2.0

查看:24
本文介绍了.NET Core 2.0 上的 JWT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在冒险让 JWT 在 DotNet 核心 2.0 上工作(现在今天达到最终版本).有大量的文档,但所有示例代码似乎都使用了已弃用的 API 并且对 Core 来说是新鲜的,弄清楚它应该如何实现确实令人眼花缭乱.我尝试使用 Jose,但 app.UseJwtBearerAuthentication 已被弃用,并且没有关于下一步做什么的文档.

I've been on quite an adventure to get JWT working on DotNet core 2.0 (now reaching final release today). There is a ton of documentation, but all the sample code seems to be using deprecated APIs and coming in fresh to Core, It's positively dizzying to figure out how exactly it's supposed to be implemented. I tried using Jose, but app. UseJwtBearerAuthentication has been deprecated, and there is no documentation on what to do next.

有没有人有一个使用 dotnet core 2.0 的开源项目,它可以简单地从授权标头解析 JWT 并允许我授权对 HS256 编码的 JWT 令牌的请求?

Does anyone have an open source project that uses dotnet core 2.0 that can simply parse a JWT from the authorization header and allow me to authorize requests for a HS256 encoded JWT token?

下面的类不会抛出任何异常,但没有请求被授权,我也没有得到任何指示为什么他们是未经授权的.响应是空的 401,所以对我来说这表明没有例外,但秘密不匹配.

The class below doesn't throw any exceptions, but no requests are authorized, and I get no indication why they are unauthorized. The responses are empty 401's, so to me that indicates there was no exception, but that the secret isn't matching.

一件奇怪的事情是我的令牌是用 HS256 算法加密的,但我没有看到任何迹象表明它强制它在任何地方使用该算法.

One odd thing is that my tokens are encrypted with the HS256 algorithm, but I see no indicator to tell it to force it to use that algorithm anywhere.

这是我目前的课程:

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Linq;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace Site.Authorization
{
    public static class SiteAuthorizationExtensions
    {
        public static IServiceCollection AddSiteAuthorization(this IServiceCollection services)
        {
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("SECRET_KEY"));

            var tokenValidationParameters = new TokenValidationParameters
            {
                // The signing key must match!
                ValidateIssuerSigningKey = true,
                ValidateAudience = false,
                ValidateIssuer = false,
                IssuerSigningKeys = new List<SecurityKey>{ signingKey },


                // Validate the token expiry
                ValidateLifetime = true,
            };

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;


            })

            .AddJwtBearer(o =>
            {
                o.IncludeErrorDetails = true;
                o.TokenValidationParameters  = tokenValidationParameters;
                o.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = c =>
                    {
                        c.NoResult();

                        c.Response.StatusCode = 401;
                        c.Response.ContentType = "text/plain";

                        return c.Response.WriteAsync(c.Exception.ToString());
                    }

                };
            });

            return services;
        }
    }
}

推荐答案

这是一个完整的带控制器的最小示例.我希望您可以使用 Postman 或 JavaScript 调用来检查它.

Here is a full working minimal sample with a controller. I hope you can check it using Postman or JavaScript call.

  1. appsettings.json、appsettings.Development.json.添加一个部分.注意,Key 应该很长,Issuer 是服务的地址:

  1. appsettings.json, appsettings.Development.json. Add a section. Note, Key should be rather long and Issuer is an address of the service:

...
,"Tokens": {
    "Key": "Rather_very_long_key",
    "Issuer": "http://localhost:56268/"
}
...

!!!在实际项目中,不要在 appsettings.json 文件中保留 Key.它应该保存在环境变量中并像这样:

!!! In real project, don't keep Key in appsettings.json file. It should be kept in Environment variable and take it like this:

Environment.GetEnvironmentVariable("JWT_KEY");

更新:了解 .net 核心设置的工作原理,您无需完全从 Environment 获取它.您可以使用设置.但是,我们可能会在生产中将此变量写入环境变量,那么我们的代码将更喜欢环境变量而不是配置.

UPDATE: Seeing how .net core settings work, you don't need to take it exactly from Environment. You may use setting. However,instead we may write this variable to environment variables in production, then our code will prefer environment variables instead of configuration.

  1. AuthRequest.cs : Dto 保留用于传递登录名和密码的值:

  1. AuthRequest.cs : Dto keeping values for passing login and password:

public class AuthRequest
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

  • Startup.cs 中的 Configure() 方法 BEFORE app.UseMvc() :

  • Startup.cs in Configure() method BEFORE app.UseMvc() :

    app.UseAuthentication();
    

  • ConfigureServices() 中的 Startup.cs :

  • Startup.cs in ConfigureServices() :

    services.AddAuthentication()
        .AddJwtBearer(cfg =>
        {
            cfg.RequireHttpsMetadata = false;
            cfg.SaveToken = true;
    
            cfg.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer = Configuration["Tokens:Issuer"],
                ValidAudience = Configuration["Tokens:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
            };
    
        });
    

  • 添加控制器:

  • Add a controller:

        [Route("api/[controller]")]
        public class TokenController : Controller
        {
            private readonly IConfiguration _config;
            private readonly IUserManager _userManager;
    
            public TokenController(IConfiguration configuration, IUserManager userManager)
            {
                _config = configuration;
                _userManager = userManager;
            }
    
            [HttpPost("")]
            [AllowAnonymous]
            public IActionResult Login([FromBody] AuthRequest authUserRequest)
            {
                var user = _userManager.FindByEmail(model.UserName);
    
                if (user != null)
                {
                    var checkPwd = _signInManager.CheckPasswordSignIn(user, model.authUserRequest);
                    if (checkPwd)
                    {
                        var claims = new[]
                        {
                            new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                            new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()),
                        };
    
                        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]));
                        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
                        var token = new JwtSecurityToken(_config["Tokens:Issuer"],
                        _config["Tokens:Issuer"],
                        claims,
                        expires: DateTime.Now.AddMinutes(30),
                        signingCredentials: creds);
    
                        return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
                    }
                }
    
                return BadRequest("Could not create token");
            }}
    

  • 就是这样!干杯!

    更新:人们问如何获取当前用户.待办事项:

    UPDATE: People ask how get Current User. Todo:

    1. 在 Startup.cs 中的 ConfigureServices() 添加

    1. In Startup.cs in ConfigureServices() add

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    

  • 在控制器中添加到构造函数:

  • In a controller add to constructor:

    private readonly int _currentUser;
    public MyController(IHttpContextAccessor httpContextAccessor)
    {
       _currentUser = httpContextAccessor.CurrentUser();
    }
    

  • 在某个地方添加一个扩展并在您的控制器中使用它(使用 ....)

  • Add somewhere an extension and use it in your Controller (using ....)

    public static class IHttpContextAccessorExtension
    {
        public static int CurrentUser(this IHttpContextAccessor httpContextAccessor)
        {
            var stringId = httpContextAccessor?.HttpContext?.User?.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
            int.TryParse(stringId ?? "0", out int userId);
    
            return userId;
        }
    }
    

  • 这篇关于.NET Core 2.0 上的 JWT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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