Dotnet core使用JWT认证授权最佳实践(一)

最近,团队的小伙伴们在做项目时,需要用到JWT认证。遂根据自己的经验,整理成了这篇文章,用来帮助理清JWT认证的原理和代码编写操作。

一、JWT

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

JWT是什么,看上面这段网上抄来的话。

关于JWT以及优缺点,网上有很多详细的说法,我这儿就不重复了。

我们只需要知道以下的事实:

在一般的系统中,我们有时候会做个用户登录。用户登录完成进到系统后,需要根据用户的权限,来控制一些功能可用,而另一些功能不可用。

在SOA/AOP架构中,做为最重要的API端,其实也需要有类似登录或认证的内容,用来区分哪些用户可以使用某个API,哪些用户不行。

同时,我们希望这个登录或类似登录的过程,只发生在一个固定位置。这样,在我们写代码时,建立好这样一个过程后,在我们后边写代码时,简单引用即可,而不需要每个API程序都开发一次认证。这个需求,其实就是OAuth的由来。

最重要的是,这样的代码写出来,显得高大上

下面进入正题。

认证这个操作,就像我们最近的日子。

首先,我们要有一个出入证,或者绿码。这个证,我们称作令牌(Token)。我们去领这个证,这个操作称为发行(Issue)。

我们拿着这个证,去到一个地方。有专人会检查这个证,这称为用户身份验证(Authentication)。验证通过放行,称为授权(Authorization),验证不通过,叫作未授权错误(Unauthorized)。

如果这个证过期了,你就需要去重新办一个证。这个过程叫做刷新(RefreshToken)。

简言之,这就是认证的全部流程。

下面,我用一个Demo项目,来逐步完成这个过程。

二、开发环境&基础项目

这个Demo的开发环境是:Mac + VS Code + Dotnet Core 3.1.2。

$ dotnet --info
.NET Core SDK (reflecting any global.json):Version:   3.1.201Commit:    b1768b4ae7Runtime Environment:OS Name:     Mac OS XOS Version:  10.15OS Platform: DarwinRID:         osx.10.15-x64Base Path:   /usr/local/share/dotnet/sdk/3.1.201/Host (useful for support):Version: 3.1.3Commit:  4a9f85e9f8.NET Core SDKs installed:3.1.201 [/usr/local/share/dotnet/sdk].NET Core runtimes installed:Microsoft.AspNetCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]Microsoft.NETCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

首先,在这个环境下建立工程:

  1. 创建Solution

% dotnet new sln -o demo
The template "Solution File" was created successfully.
  1. 用Webapi模板创建项目

% cd demo
% dotnet new webapi -o demo
The template "ASP.NET Core Web API" was created successfully.Processing post-creation actions...
Running 'dotnet restore' on demo/demo.csproj...Restore completed in 179.13 ms for demo/demo.csproj.Restore succeeded.
  1. 把Demo项目加到Solution中

% dotnet sln add demo/demo.csproj
Project `demo/demo.csproj` added to the solution.
  1. 安装Swagger(这步非必须,我习惯用Swagger,不习惯用Postman)

% dotnet add package Swashbuckle.AspNetCore
log  : Restore completed in 2.75 sec for demo/demo.csproj.
  1. 安装JWT认证支持库(必须引入)

% dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
log  : Restore completed in 3.09 sec for demo/demo.csproj.

五步做完,基础项目就建完了。

看一下整个的目录结构:

% tree .
.
├── demo
│   ├── Controllers
│   │   └── WeatherForecastController.cs
│   ├── Program.cs
│   ├── Properties
│   │   └── launchSettings.json
│   ├── Startup.cs
│   ├── WeatherForecast.cs
│   ├── appsettings.Development.json
│   ├── appsettings.json
│   ├── demo.csproj
│   └── obj
│       ├── demo.csproj.nuget.dgspec.json
│       ├── demo.csproj.nuget.g.props
│       ├── demo.csproj.nuget.g.targets
│       ├── project.assets.json
│       └── project.nuget.cache
└── demo.sln

  1. 在Startup.cs中补充代码,以启用Swagger

在ConfigureServices方法中加入以下代码:

services.AddSwaggerGen(c =>
{c.SwaggerDoc("v1", new OpenApiInfo { Title = "Demo", Version = "V1" });c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{Name = "Authorization",Type = SecuritySchemeType.ApiKey,Scheme = "Bearer",BearerFormat = "JWT",In = ParameterLocation.Header,Description = "",});c.AddSecurityRequirement(new OpenApiSecurityRequirement{{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},new string[] {}}});
});

在Configure方法中加入以下代码

app.UseSwagger();
app.UseSwaggerUI(c =>
{c.SwaggerEndpoint("/swagger/v1/swagger.json", "Demo V1");
});

关于Swagger的详细配置,这里不做说明,留着以后写。

三、签发Token

签发Token是认证的第一步。

用户进到系统,在验证用户帐号密码后,需要根据用户的数据,把Token返回给用户。

这个过程其实跟认证没什么关系,只是一个普通的API功能。

  1. 工程下加一个目录DTOModels,创建一个LoginRequestDTO的类,用于定义API的输入参数。

using System;namespace demo.DTOModels
{public class LoginRequestDTO{public string username { get; set; }public string password { get; set; }}
}
  1. 创建一个控制器AuthenticationController,并在控制器里创建一个API方法RequestToken。

using Microsoft.AspNetCore.Mvc;
using demo.DTOModels;namespace demo.Controllers
{public class AuthenticationController : ControllerBase{[HttpPost, Route("requesttoken")]public ActionResult RequestToken([FromBody] LoginRequestDTO request){//这儿待完善return Ok();}}
}
  1. 生成JWT Token需要预设一些参数。我们在appsetting.json里先设置好。

{"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","tokenParameter": {"secret": "123456123456123456","issuer": "WangPlus","accessExpiration": 120,"refreshExpiration": 1440}
}

这里,tokenParameter节是我们设置的参数。一般来说,是这几个:

secret: JWT加密的密钥。现在主流用SHA256加密,需要256位以上的密钥,unicode是16个字符以上,尽量复杂一些。密钥泄露,Token就会被破解,所以,你懂的。

issuer: 签发人的名称,如果没人注意,你可以把大名写在上面。

accessExpiration: Token的有效分钟数。过了这个时间,这个Token会过期。

refreshExpiration: refreshToken的有效分钟数。过了这个时间,用户需要重新登录。

Token过期后,可以让用户重新登录认证拿Token。但这个方式会比较Low。高大上的方式是签发Token的时候,同时也签发一个refreshToken给用户。用户Token过期后,可以拿refreshToken去申请新的Token,同时刷新refreshToken。如果用户长时间未使用系统,refreshToken也过期了,才让用户重新登录认证。

refreshToken可以用JWT生成,也可以自己生成,不影响认证。

  1. 建一个Models目录,创建一个映射tokenParameter的类。这个类不是必须,只是为了写着方便。不想这样写,也可以直接读配置,再转成数据。

using System;namespace demo.Models
{public class tokenParameter{public string Secret { get; set; }public string Issuer { get; set; }public int AccessExpiration { get; set; }public int RefreshExpiration { get; set; }}
}
  1. 在前边建好的API - RequestToken中,完成Token和refreshToken的生成和返回。

using Microsoft.AspNetCore.Mvc;
using demo.DTOModels;
using Microsoft.Extensions.Configuration;
using System;
using System.Text;
using demo.Models;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;namespace demo.Controllers
{public class AuthenticationController : ControllerBase{private tokenParameter _tokenParameter = new tokenParameter();public AuthenticationController(){var config = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory).AddJsonFile("appsettings.json").Build();_tokenParameter = config.GetSection("tokenParameter").Get<tokenParameter>();}[HttpPost, Route("requestToken")]public ActionResult RequestToken([FromBody] LoginRequestDTO request){//这儿在做用户的帐号密码校验。我这儿略过了。if (request.username == null && request.password == null)return BadRequest("Invalid Request");//生成Token和RefreshTokenvar token = GenUserToken(request.username, "testUser");var refreshToken = "123456";return Ok(new[] { token, refreshToken });}//这儿是真正的生成Token代码private string GenUserToken(string username, string role){var claims = new[]{new Claim(ClaimTypes.Name, username),new Claim(ClaimTypes.Role, role),};var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenParameter.Secret));var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var jwtToken = new JwtSecurityToken(_tokenParameter.Issuer, null, claims, expires: DateTime.UtcNow.AddMinutes(_tokenParameter.AccessExpiration), signingCredentials: credentials);var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);return token;}}
}

这个类里,验证帐号密码的代码我略过了。还有,refreshToken给了一个固定串。真实项目这儿就按需要做就好。

(未完待续)

动动手指,点个在看

您的赞赏是我最大的鼓励

I will be more solid with your donations

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java基础]反射获取成员变量并使用

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

2018年蓝桥杯B组题E题+快排

题目&#xff1a; E 快速排序&#xff1a;以下代码可以从数组a[]中找出第k小的元素。 它使用了类似快速排序中的分治算法&#xff0c;期望时间复杂度是O(N)的。 请仔细阅读分析源码&#xff0c;填写划线部分缺失的内容。 #include <stdio.h> int quick_select(int a[],…

Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权

在上一讲中&#xff0c;我们已经完成了一个完整的案例&#xff0c;在这个案例中&#xff0c;我们可以通过Angular单页面应用&#xff08;SPA&#xff09;进行登录&#xff0c;然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证。在本讲中&#xff0c;我们会讨论在当…

[Java基础]反射获取成员变量并使用练习

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)

上一篇文章使用AutoMapper来处理对象与对象之间的映射关系&#xff0c;本篇主要围绕定时任务和数据抓取相关的知识点并结合实际应用&#xff0c;在定时任务中循环处理爬虫任务抓取数据。开始之前可以删掉之前测试用的几个HelloWorld&#xff0c;没有什么实际意义&#xff0c;直…

题目 2285: [蓝桥杯][2018年第九届真题]螺旋折线(数论+思维)

题目&#xff1a; 题目描述 如图所示的螺旋折线经过平面上所有整点恰好一次。 对于整点(X, Y)&#xff0c;我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。 例如dis(0, 1)3, dis(-2, -1)9 给出整点坐标(X, Y)&#xff0c;你能计算出dis(X, Y)吗&…

[Java基础]反射获取成员方法并使用练习

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

读懂操作系统之虚拟内存(一)

由于个人对虚拟内存这块特别感兴趣&#xff0c;所以就直接暂且跳过其他&#xff0c;接下来将通过几篇文章进行详细讲解&#xff0c;当然其他基础内容后续在我进行相应整体学习后也会同步输出文章&#xff0c;比如操作系统概念、程序链接、进程管理、页面置换算法、流水线、浮点…

[Java基础]反射练习之越过泛型检查,运行配置文件制定内容

代码如下: package ReflectTest01;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList;public class ReflectTest01 {public static void main(String[] args) throws NoSuchMethodException, InvocationTarg…

【Ids4实战】深究配置——用户信息操作篇

&#xff08;此花无日不春风&#xff09;其实IdentityServer4的小项目已经基本完结了&#xff0c;但是我总感觉还是有很多东西没有深入挖掘和研究的&#xff0c;这不&#xff0c;二群里有小伙伴问到了一个常见的问题&#xff0c;因为我去年都见到了&#xff0c;一直没有想过去解…

Sql Server之旅——第九站 看看DML操作对索引的影响

我们都知道建索引是需要谨慎的&#xff0c;当只有利大于弊的时候才适合建&#xff0c;同时也知道建索引是需要维护成本的&#xff0c;这个维护也就在于DML操作&#xff0c;下面具体看看到底DML对索引都有哪些内幕。。。。一&#xff1a;delete操作现在大家都已经知道索引是以B树…

[Java基础]反射获取成员方法并使用

代码如下: package ClassObjectPack01;import ClassObjectPack.Student;import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;public class ReflectDemo05 {public static void main(String[] args)…

副业刚需? 恐怕并不靠谱!

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份上一篇文章推了我的星球&#xff0c;两天时间就有接近200位读者加入。有「热心朋友」帮我计算了下&#xff1a;你这两天收入快2万啊&#xff0c;你这副业做的挺好啊。很不客气的说&#xff0c;如果写写公号&a…

[Java基础]Junit测试

Junit测试: 代码如下: package CalculatorPack;public class Calculator {public int add(int a,int b){return ab;}public int sub(int a,int b){return a-b;}}package CalculatorPack;import org.junit.Assert; import org.junit.Test;public class CalculatorTest {Testp…

15分钟为自己架设优雅如Github的代码仓库

前言Github大家都熟悉。除了开源的项目外&#xff0c;有时候&#xff0c;大家也会把自己或团队、公司的项目传到Github的私有仓库里&#xff0c;把Github当成自己的私人Git Server。但是&#xff0c;用Github会有一些问题&#xff1a;Github从国内访问不是很稳定&#xff0c;有…

Pseudoprime numbers POJ - 3641(快速幂+判素数)

题意&#xff1a; 给你两个数&#xff0c;p和a&#xff1b;满足两个条件&#xff1a; 1.p不是素数&#xff1b; 2.apa^{p}ap %pa; 满足则输出yes&#xff0c;反之输出no。 题目&#xff1a; Fermat’s theorem states that for any prime number p and for any integer a &g…

[Java基础]反射案列

pro.properties文件(该文件与ReflectTest01同处在同一个文件夹)&#xff1b; className domain.Person methodName eat代码如下: package domain;public class Student {public void sleep(){System.out.println("sleep...");} }package domain;public class Per…

[推荐]大量 Blazor 学习资源(三)

大量 Blazor 学习资源系列文章&#xff1a;[推荐]大量 Blazor 学习资源&#xff08;一&#xff09;[推荐]大量 Blazor 学习资源&#xff08;二&#xff09;这次主要内容有 Blazor 相关视频&#xff0c;因为本身视频是英文的&#xff0c;所以就保持原样了&#xff0c;描述没有翻…