700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > .Net Core WebApi集成JWT实现身份认证

.Net Core WebApi集成JWT实现身份认证

时间:2021-05-03 22:01:37

相关推荐

.Net Core WebApi集成JWT实现身份认证

前言

最近有朋友问我jwt的使用,有感而发写篇文章,由于一直使用框架开发,这些技术还真有些手生了,特此写篇文章做下笔记。

随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。适用于多客户端的前后端解决方案,JWT 是无状态化的,更适用于 RESTful 风格的接口验证。本文主要介绍使用JWT进行接口身份认证。

jwt介绍

JWT的结构体是什么样的?

JWT由三部分组成,分别是头信息、有效载荷、签名,中间以(.)分隔

(1)header(头信息) 描述 JWT 的元数据的JSON对象

由两部分组成,令牌类型(即:JWT)、散列算法(HMAC、RSASSA、RSASSA-PSS等)

{"alg":"HS256","typ":"JWT"}

(2)Payload(有效载荷)

JWT的第二部分是payload,其中包含claims。claims是关于实体(常用的是用户信息)和其他数据的声明,claims有三种类型: registered, public, and private claims。

一个用来存放实际需要传递的数据的JSON 对象。如:

"/ws//05/identity/claims/name": "admin","exp": 1610877510,"iss": "cba","aud": "cba"}

(3)Signature

要创建签名部分,必须采用编码的Header,编码的Payload,秘钥,Header中指定的算法,并对其进行签名。 对前两部分(Header、Payload)的签名,防止数据篡改。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

JWT示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE2MTA4Nzc1MTAsImlzcyI6ImNiYSIsImF1ZCI6ImNiYSJ9.O9lbZwfqRuA6vKcRCfYieA1zLkTPppdSvTc8UzwCkNw

一.准备工作

Demo可以在我的资源中下载 Demo

/download/qq_39569480/24392815

(1).添加NuGet程序包

Microsoft.AspNetCore.Authentication.JwtBearer

(2).appsettings.json

"JwtConfig": {"SecretKey": "123123123123", // 密钥 可以是guid 也可以是随便一个字符串"Issuer": "zhangsan", // 颁发者"Audience": "zhangsan", // 接收者"Expired": 30 // 过期时间(30min)},

二.创建JWT配置类

using Microsoft.Extensions.Options;using Microsoft.IdentityModel.Tokens;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/// <summary>/// jwt配置/// </summary>public class JwtConfig : IOptions<JwtConfig>{public JwtConfig Value => this;public string SecretKey {get; set; }public string Issuer {get; set; }public string Audience {get; set; }public int Expired {get; set; }public DateTime NotBefore => DateTime.UtcNow;public DateTime IssuedAt => DateTime.UtcNow;public DateTime Expiration => IssuedAt.AddMinutes(Expired);private SecurityKey SigningKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));public SigningCredentials SigningCredentials =>new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256);}

三.创建JWT工具类

public class GenerateJwt{private readonly JwtConfig _jwtConfig;public GenerateJwt(IOptions<JwtConfig> jwtConfig){_jwtConfig = jwtConfig.Value;}/// <summary>/// 生成token/// </summary>/// <param name="sub"></param>/// <param name="customClaims">携带的用户信息</param>/// <returns></returns>public JwtTokenResult GenerateEncodedTokenAsync(string sub, LoginUserModel customClaims){//创建用户身份标识,可按需要添加更多信息var claims = new List<Claim>{new Claim("userid", customClaims.userid),new Claim("username", customClaims.username),//new Claim("realname",customClaims.realname),//new Claim("roles", string.Join(";",customClaims.roles)),//new Claim("permissions", string.Join(";",customClaims.permissions)),//new Claim("normalPermissions", string.Join(";",customClaims.normalPermissions)),new Claim(JwtRegisteredClaimNames.Sub, sub),};//创建令牌var jwt = new JwtSecurityToken(issuer: _jwtConfig.Issuer,audience: _jwtConfig.Audience,claims: claims,notBefore: _jwtConfig.NotBefore,expires: _jwtConfig.Expiration,signingCredentials: _jwtConfig.SigningCredentials);string access_token = new JwtSecurityTokenHandler().WriteToken(jwt);return new JwtTokenResult(){access_token = access_token,expires_in = _jwtConfig.Expired * 60,token_type = JwtBearerDefaults.AuthenticationScheme,user = customClaims};}}

四.JwtTokenResult

登录成功生成jwt返回给前端的model,LoginUserModel是用户信息model,我这里携带是为了避免前端解析token。

/// <summary>/// 登录成功返回model/// </summary>public class JwtTokenResult{public string access_token {get; set; }public string refresh_token {get; set; }/// <summary>/// 过期时间(单位秒)/// </summary>public int expires_in {get; set; }public string token_type {get; set; }public LoginUserModel user {get; set; }}public class LoginUserModel{public string userid {get; set; }public string username {get; set; }public string realname {get; set; }public string roles {get; set; }public string permissions {get; set; }public string normalPermissions {get; set; }}

五.Startup配置

(1) .ConfigureServices注入jwt

//注入jwtservices.AddScoped<GenerateJwt>();services.Configure<JwtConfig>(Configuration.GetSection("JwtConfig"));#region jwt验证var jwtConfig = new JwtConfig();Configuration.Bind("JwtConfig", jwtConfig);services.AddAuthentication(option =>{//认证middleware配置option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options =>{options.TokenValidationParameters = new TokenValidationParameters{//Token颁发机构ValidIssuer = jwtConfig.Issuer,//颁发给谁ValidAudience = jwtConfig.Audience,//这里的key要进行加密IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecretKey)),//是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比ValidateLifetime = true,};});#endregion

(2).Configure

app.UseAuthentication();//要在授权之前认证

六.调用获取token

using JwtDemo.Model;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace JwtDemo.Controllers{[Route("api/[controller]/[action]")][ApiController]public class TestController : Controller{private readonly GenerateJwt _generateJwt;public TestController(GenerateJwt generate) {this._generateJwt = generate;}[HttpGet]public ActionResult GetLogin(string name,string userid) {var claims = new LoginUserModel(){userid = userid,username = name,realname = name,//roles = string.Join(";", user.roles),//permissions = string.Join(";", user.permissions), };var refreshToken = Guid.NewGuid().ToString(); //当然 你要在生成token之前要验证一下账户是否在数据库存在 存在则生成/*数据库查询*/var jwtTokenResult = _generateJwt.GenerateEncodedTokenAsync(userid, claims);jwtTokenResult.refresh_token = refreshToken;return Json(jwtTokenResult);//这里可按需返回 如果不想返回用户信息 比如密码 可以在_generateJwt.GenerateEncodedTokenAsync去掉哦}}}

swagger调试

postman请求

七.在后台中有时候我们需要获取当前用户的一些属性

JwtUser,用户解析jwt 获取当前用户信息

public static class JwtUser{/// <summary>/// 解析jwt 获取当前用户信息/// </summary>/// <param name="request"></param>/// <returns>用户信息</returns>public static LoginUserModel GetRequestUser(this HttpRequest request){var authorization = request.Headers["Authorization"].ToString();var auth = authorization.Split(" ")[1];var jwtArr = auth.Split('.');var dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));//解析Claimsvar reqUser = new LoginUserModel{userid = dic["userid"],username = dic["username"],realname = dic["realname"],roles = dic["roles"],permissions = dic["permissions"],normalPermissions = dic["normalPermissions"],};return reqUser;} }

控制器中这样获取

[HttpGet]public ActionResult GetUser() {var aa= JwtUser.GetRequestUser(this.Request);return Json(aa.userid+"===="+ aa.username); //获取到当前用户的姓名 角色等等就可以做一些业务处理}

八.使用

在接口上标记身份验证

[AllowAnonymous] 标记此标识的接口是不需要验证的

[Authorize] 标记此标识的接口需要验证

[Authorize][HttpGet] public ActionResult GetDataList(string 参数){/*业务代码*/return Json("");}

也可以直接标记在控制器上

获取token的接口最好单独写在一个控制器

九.Swagger UI添加认证

在项目中通常都添加了Swagger UI来展示接口及基础测试,那么如果添加了认证后,如何在调用接口前添加认证信息呢?

在Startup中:ConfigureServices中添加Swagger设置时,添加认证设置

#region 启用swagger验证功能//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称一致即可。c.AddSecurityRequirement(new OpenApiSecurityRequirement{{new OpenApiSecurityScheme{Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme,Id = "Bearer"}},new string[] {}}});c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",Name = "Authorization",//jwt默认的参数名称In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)Type = SecuritySchemeType.ApiKey,BearerFormat = "JWT",Scheme = "Bearer",});#endregion

添加token即可

输入时 要输入Bearer +token 注意Bearer后有空格

ok感谢观看

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。