首页 > 技术文章 > Asp.net Core Jwt简单使用

liessay 2020-12-07 15:32 原文

.net 默认新建Api项目不需要额外从Nuget添加Microsoft.AspNetCore.Authentication.JwtBearer

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "Authentication": {
    //私钥必须16位
    "SecretKey": "YpdCP1VHoWkNawmb",
    //谁签发的(发布者)
    "issuer": "issuer",
    //签发给谁(持有者)
    "audience": "audience"
  } 
}

AuthController,具体登录实现可参考我以前文章Identity用户管理入门五(登录、注销) 

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Shop.WebHost.Controllers
{
    [Route("auth")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private readonly IConfiguration _configuration;

        public AuthController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        // GET: api/<AuthController>
        [AllowAnonymous]
        [HttpPost("Login")]
        public ActionResult Login([FromForm] UserDto loginUser)
        {
            //模拟登陆用户提交数据
            //以下假设登陆验证通过

            // JWT主要由三部分组成:HEADER.PAYLOAD.SIGNATURE

            // HEADER,加密算法和签名的类型,加密算法是HmacSha256
            const string signingAlgorithm = SecurityAlgorithms.HmacSha256;

            //Payload,如用户名,角色等信息,过期日期等,因为是未加密的,所以不建议存放敏感信息。
            var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, "user_id"), //红色字体为登录后获取的实际用户ID
//用户角色
new Claim(ClaimTypes.Role,"Admin"), //红色字体为用户登录后获取的实际用户角色
};
            //Signiture从配置文件获取私钥
            var secretByte = Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]);
            //使用非对称算法对私钥进行加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            //使用HmacSha256验证非对称加密后的私钥
            var signingCredentials = new SigningCredentials(signingKey, signingAlgorithm);

            //创建Jwt Token
            var token = new JwtSecurityToken(
                //谁发布的token
                issuer: _configuration["Authentication:issuer"],
                //发布给谁
                audience: _configuration["Authentication:audience"],
                //Payload
                claims,
                //发布时间
                notBefore: DateTime.UtcNow,
                //有效期s
                expires: DateTime.UtcNow.AddDays(1),
                //数字签名
                signingCredentials
                );
            return Ok(new JwtSecurityTokenHandler().WriteToken(token));
        }
    }

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

Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;

namespace Shop.WebHost
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            //Jwt认证服务
            //AddAuthentication注册认证服务
            //JwtBearerDefaults.AuthenticationScheme身份认证类型
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                //Jwt身份认证
                .AddJwtBearer(option =>
                {
                    //从配置文件读取私钥
                    var secretByte= Encoding.UTF8.GetBytes(Configuration["Authentication:SecretKey"]);
                    //身份认证参数
                    option.TokenValidationParameters = new TokenValidationParameters()
                    {
                        //验证发布者
                        ValidateIssuer = true,
                        ValidIssuer = Configuration["Authentication:issuer"],

                        //验证持有者
                        ValidateAudience = true,
                        ValidAudience = Configuration["Authentication:audience"],

                        //验证是否过期
                        ValidateLifetime = true,

                        //加密私钥
                        IssuerSigningKey = new SymmetricSecurityKey(secretByte)
                    };
                });
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Shop.WebHost", Version = "v1" });
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Shop.WebHost v1"));
            }

            app.UseHttpsRedirection();

            //你在哪
            app.UseRouting();
            //你是谁
            app.UseAuthentication();
            //你可以干什么
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

在控制器方法中增加【Authorize】即可未登录用户不能访问

控制用户组访问[Authorize(Roles = "Admin")] 

// 由于我们没有将身份验证中间件配置为自动运行并创建身份,
// 因此在授权时必须选择要使用的中间件。
// 选择要授权的中间件的最简单方法是使用ActiveAuthenticationSchemes属性
[Authorize(AuthenticationSchemes = "Bearer")]

访问方式在header中增加(具体格式是Authorization:Bearer+空格+具体Token

Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyX2lkIiwibmJmIjoxNjA3MzI1NzkxLCJleHAiOjE2MDc0MTIxOTEsImlzcyI6Imlzc3VlciIsImF1ZCI6ImF1ZGllbmNlIn0.ZEN3m7XP8u-u9CNkVf1tfeznqh1SuK7Y0wD1bq9rSfQ

获取当前登录用户ID

startup.cs增加HttpContextAccessor服务并注入HttpContext的访问器对象IHttpContextAccessor来获取当前的HttpContext

services.AddHttpContextAccessor();
private readonly IHttpContextAccessor _httpContextAccessor;

public AuthController(IHttpContextAccessor httpContextAccessor)
{
    _httpContextAccessor = httpContextAccessor;
}

增加获取当前用户ID方法

[HttpGet(nameof(GetCurrUserIdAsync))]
public async Task<string> GetCurrUserIdAsync()
{
    var auth = await _httpContextAccessor.HttpContext!.AuthenticateAsync();//获取登录用户的AuthenticateResult
    if (!auth.Succeeded) return null;
    var userCli = auth.Principal?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier); //在声明集合中获取ClaimTypes.NameIdentifier 的值就是用户ID
    if (userCli == null || string.IsNullOrEmpty(userCli.Value))
    {
        return null;
    }
    return userCli.Value;
}

或者使用

return _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;

查询出当前用户ID就可以根据Identity用户管理入门二(显示用户列表)显示用户详情

推荐阅读