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

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

问题描述

我一直在冒险,让JWT在DotNet core 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的开源项目,该项目可以简单地从授权标头解析J​​WT,并允许我授权对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.

这是我到目前为止的课程:

Here is the class I have so far:

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.添加一个部分.注意,密钥应相当长,并且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/"
}
...

!!!在实际项目中,请勿将Key保留在appsettings.json文件中.应该将其保存在Environment变量中,并采用以下方式:

!!! 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; }
}

在app.UseMvc()之前,Configure()方法中的

  • Startup.cs:

  • 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();
    }
    

  • 在某处添加扩展名并在您的Controller中使用它(使用....)

  • 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天全站免登陆