龙空技术网

JWT+ASP.NET Core集成方案

IT技术资源爱好者 790

前言:

目前同学们对“net core doc”大体比较关切,兄弟们都需要分析一些“net core doc”的相关知识。那么小编也在网络上收集了一些关于“net core doc””的相关知识,希望姐妹们能喜欢,咱们一起来了解一下吧!

JWT

JSON Web Token 经过数字签名后,无法伪造,一个能够在各方之间安全的传输JSON对象的开放标准(RFC 7519)

参考前文 [翻译]Introduction to JSON Web Tokens - 、天上月 - 博客园 (cnblogs.com)创建项目和解决方案

dotnet new webapi -n SampleApicd SampleApidotnet new sln -n SampleAppdotnet sln  add .\SampleApi.csproj
引用包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

该包已经依赖Microsoft.IdentityModel.TokensSystem.IdentityModel.Tokens.Jwt,该包由Azure AD 团队提供,所以不在aspnetcore6 运行时中。

或直接修改jwtaspnetcore.csproj,引用包

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
appsettings.json
  "Authentication": {    "JwtBearer": {      "Issuer": ";,      "Audience": "SampleApi",      "SecurityKey": "SecurityKey23456"    }  }
Issuer:令牌的颁发者。一般就写成域名,实际可任意Audience 颁发给谁。一般写成项目名,实际可任意SecurityKey:签名验证的KEY;至少 128bit ,即16个英文字符以上,实际可任意英文字符定义一个JwtSettings
public class JwtSettings{    public JwtSettings(byte[] key, string issuer, string audience)    {        Key = key;        Issuer = issuer;        Audience = audience;    }    /// <summary>    ///令牌的颁发者    /// </summary>    public string Issuer { get; }    /// <summary>    /// 颁发给谁    /// </summary>    public string Audience { get; }    public byte[] Key { get; }    public TokenValidationParameters TokenValidationParameters => new TokenValidationParameters    {        //验证Issuer和Audience        ValidateIssuer = true,        ValidateAudience = true,        ValidateIssuerSigningKey = true,        //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比        ValidateLifetime = true,        ValidIssuer = Issuer,        ValidAudience = Audience,        IssuerSigningKey = new SymmetricSecurityKey(Key)    };    public static JwtSettings FromConfiguration(IConfiguration configuration)    {        var issuser = configuration["Authentication:JwtBearer:Issuer"] ?? "default_issuer";        var auidence = configuration["Authentication:JwtBearer:Audience"] ?? "default_auidence";        var securityKey = configuration["Authentication:JwtBearer:SecurityKey"] ?? "default_securitykey";        byte[] key = Encoding.ASCII.GetBytes(securityKey);        return new JwtSettings(key, issuser, auidence);    }}

中间件Middleware引用

        app.UseAuthentication();//认证        app.UseAuthorization();//授权

定义JWT扩展方法服务注入

    public static IServiceCollection AddJwt(this IServiceCollection services, IConfiguration configuration)    {        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();        services.AddScoped<IStorageUserService, StorageUserService>();        var jwtSettings = JwtSettings.FromConfiguration(configuration);        services.AddSingleton(jwtSettings);        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)                .AddJwtBearer(options => options.TokenValidationParameters = jwtSettings.TokenValidationParameters);        return services;    }
引用服务
services.AddJwt(Configuration);

定义一个数据库的实体类,数据库访问 为模拟数据

public class SysUser{    public int Id { get; set; }    public string UserName { get; set; }}
public interface IStorageUserService{    /// <summary>    /// 根据登录验证用户    /// </summary>    /// <param name="loginInfo"></param>    /// <returns></returns>    Task<SysUser> CheckPasswordAsync(LoginInfo loginInfo);}public class StorageUserService : IStorageUserService{    public async Task<SysUser> CheckPasswordAsync(LoginInfo loginInfo)    {        return await Task.FromResult(          new SysUser           {             Id = new Random().Next(10000),             UserName = loginInfo.UserName           }        );    }}
AuthController登录GenerateToken
using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using Microsoft.IdentityModel.Tokens;using SampleApi.Models;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;namespace SampleApi.Auth;/// <summary>/// 登录认证个人信息/// </summary>[ApiController][Route("/api/[controller]/[action]")][AllowAnonymous]public class AuthController : ControllerBase{    private readonly IStorageUserService _userService;    private readonly JwtSettings _jwtSettings;    public AuthController(JwtSettings jwtSettings, IStorageUserService userService)    {        _jwtSettings = jwtSettings;        _userService = userService;    }    /// <summary>    /// 登录,生成访问Toekn    /// </summary>    /// <param name="loginInfo"></param>    /// <returns></returns>    [HttpPost]    public async Task<IActionResult> GenerateToken(LoginInfo loginInfo)    {        SysUser user = await _userService.CheckPasswordAsync(loginInfo);        if (user == null)        {            return Ok(new            {                Status = false,                Message = "账号或密码错误"            });        }        var claims = new List<Claim>();        claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));        claims.Add(new Claim(ClaimTypes.Name, user.UserName));        var key = new SymmetricSecurityKey(_jwtSettings.Key);        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);        var token = new JwtSecurityToken(            issuer: _jwtSettings.Issuer,            audience: _jwtSettings.Audience,            claims: claims,            expires: DateTime.Now.AddMinutes(120),            signingCredentials: creds            );        return Ok(new        {            Status = true,            Token = new JwtSecurityTokenHandler().WriteToken(token)        });    }}

aspnetcore6默认集成了swagger,直接运行项目,实际上为模拟数据库请求,所以点击登录接口即可。

{  "status": true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6Ijc4NjciLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoic3RyaW5nIiwiZXhwIjoxNjQzMDMyNzA1LCJpc3MiOiJodHRwOi8vYXBpLnNhbXBsZWFwaS5jb20iLCJhdWQiOiJTYW1wbGVBcGkifQ.Rl8XAt2u0aZRxEJw2mVUnV6S9WzQ65qUYjqXDTneCxE"}

当使用Swagger测试时,增加,可配置全局请求头。增加一个扩展方法。

services.AddSwagger(Configuration);
  public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration)    {        services.AddSwaggerGen(options =>        {            try            {                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"), true);            }            catch (Exception ex)            {                Log.Warning(ex.Message);            }            options.SwaggerDoc("v1", new OpenApiInfo            {                Title = "SampleApp - HTTP API",                Version = "v1",                Description = "The SampleApp Microservice HTTP API. This is a Data-Driven/CRUD microservice sample"            });            options.AddSecurityRequirement(new OpenApiSecurityRequirement()                {                    {                        new OpenApiSecurityScheme                        {                            Reference = new OpenApiReference()                            {                                Id =  "Bearer",                                Type = ReferenceType.SecurityScheme                            }                        },                        Array.Empty<string>()                    }                });            options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme            {                Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",                Name = "Authorization", //jwt默认的参数名称                In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)                Type = SecuritySchemeType.ApiKey            });        });        services.AddEndpointsApiExplorer();        return services;    }
获取当前用户信息
    /// <summary>    /// 编码Token    /// </summary>    /// <param name="token"></param>    /// <returns></returns>    [HttpGet]    [AllowAnonymous]    public CurrentUser DecodeToken(string token)    {        var jwtTokenHandler = new JwtSecurityTokenHandler();        if (jwtTokenHandler.CanReadToken(token))        {            JwtPayload jwtPayload = new JwtSecurityTokenHandler().ReadJwtToken(token).Payload;            string? userIdOrNull = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.NameIdentifier)?.Value;            string? UserName = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.Name)?.Value;            CurrentUser currentUser = new CurrentUser            {                UserId = userIdOrNull == null ? null : Convert.ToInt32(userIdOrNull),                UserName = UserName            };            return currentUser;        }        return null;    }
根据请求头获取用户信息

IStorageUserService增加接口,StorageUserService的实现,创建一个CurrentUser类

public class StorageUserService : IStorageUserService{    private readonly IHttpContextAccessor _contextAccessor;    public StorageUserService(IHttpContextAccessor contextAccessor)    {        _contextAccessor = contextAccessor;    }    public async Task<CurrentUser> GetUserByRequestContext()    {        var user = _contextAccessor.HttpContext.User;        string? userIdOrNull = user.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;        string? UserName = user.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;        CurrentUser currentUser = new CurrentUser        {            IsAuthenticated = user.Identity.IsAuthenticated,            UserId = userIdOrNull == null ? null : Convert.ToInt32(userIdOrNull),            UserName = UserName        };        return await Task.FromResult(currentUser);    }}public class CurrentUser{    /// <summary>    /// 是否登录    /// </summary>    public bool IsAuthenticated { get; set; }    /// <summary>    /// 用户Id    /// </summary>    public int? UserId { get; set; }    /// <summary>    /// 用户名    /// </summary>    public string? UserName { get; set; }}public interface IStorageUserService{    /// <summary>    /// 根据Request Header携带Authorization:Bearer+空格+AccessToken获取当前登录人信息    /// </summary>    /// <returns></returns>    Task<CurrentUser> GetUserByRequestContext();}
AuthController调用服务
    /// <summary>    /// 根据Request Header携带Authorization:Bearer+空格+AccessToken获取当前登录人信息    /// </summary>    /// <returns></returns>    [HttpGet]    [Authorize]    public async Task<CurrentUser> GetUserByRequestContext()    {        return await _userService.GetUserByRequestContext();    }

在swagger右上角,点击Authorize,header的参数结构: "Authorization: Bearer+空格+ {token}"

原文连接:

欢迎点赞+转发+关注!大家的支持是我分享最大的动力!!!

标签: #net core doc