c# - .NET Core 2.0 上的智威汤逊

标签 c# .net-core jwt jose

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

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

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

一件奇怪的事是我的 token 是用 HS256 算法加密的,但我看不到任何指示器告诉它强制它在任何地方使用该算法。

这是我目前的类(class):

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

最佳答案

这是一个带有 Controller 的完整工作最小示例。我希望你可以使用 Postman 或 JavaScript 调用来检查它。

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

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

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

    Environment.GetEnvironmentVariable("JWT_KEY");
    

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

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

    public class AuthRequest
    {
        public string UserName { get; set; }
        public string Password { get; set; }
    }
    
  2. Startup.cs 在 Configure() 方法中,在 app.UseMvc() 之前:

    app.UseAuthentication();
    
  3. ConfigureServices() 中的 Startup.cs:

    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"]))
            };
    
        });
    
  4. 添加 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");
            }}
    

这就是所有人!干杯!

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

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

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    
  2. 在 Controller 中添加到构造函数:

    private readonly int _currentUser;
    public MyController(IHttpContextAccessor httpContextAccessor)
    {
       _currentUser = httpContextAccessor.CurrentUser();
    }
    
  3. 在某处添加一个扩展并在您的 Controller 中使用它(使用....)

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

关于c# - .NET Core 2.0 上的智威汤逊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45686477/

相关文章:

asp.net-mvc - 续订 Azure ACS 颁发的 JWT

.net - 安装了多个.net核心SDK(不同版本),我可以保持最新吗?

c# - 运行时编译期间收到 “You must add a reference to assembly ' netstandard'”错误

php - Botman laravel REST API 设置

带有 JWT 的 AngularJS 或 SPA - 到期和刷新

c# - 无法通过命名管道发送 protobuf 流并取回结果

c# - GridView 仅显示第一个检索到的记录

c# - 什么是 VS2013 中的 LinqToXsdSchema 构建操作?

c# - 服务器表单中的 ASP.net paypal 表单

c# - 错误 NU1100 : Unable to resolve 'Microsoft. AspNetCore.SpaServices.Extensions