jwt是做验证的必经之路,至于原理,就不在叙述了,可以参考官网
jwt官网介绍
JSON Web Tokens - jwt.io
原理介绍
JSON Web Token 入门教程 - 阮一峰的网络日志
看完之后,结合这个图,就明白了。
本案例使用vs2022,.net6api做后端,以及vue3做前端来完成功能。
1.创建一个可执行的.net6api后端
2.安装jwt,要注意版本
- 在appsettings.json中添加JWT加密需要的私钥AuthenticationDemo
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AuthenticationDemo": { //这些键值对都可以自定义
"SecretKeyDemo": "aaaaaaaaaadddddddddddddffffffffffffwwwwwwww", //私钥
"IssuerDemo": "guli2130", //发布者
"AudienceDemo": "audience" //接收者
}
}
4.新建一个GetToken类,再建立一个LoginToken方法
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace net6ApiJWT.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class GetToken : ControllerBase
{
public readonly IConfiguration configuration;
public GetToken(IConfiguration configuration) //注入配置,用来获取appsettings.json的配置
{
this.configuration = configuration;
}
[HttpGet]
public ActionResult<string> LoginToken()
{
//1.验证用户账号密码是否正确,暂时忽略,因为我们是模拟登录
//2.生成JWT
//Header,选择签名算法
var signingAlogorithm = SecurityAlgorithms.HmacSha256;
//Payload,存放用户信息,下面我们放了一个用户id
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub,"userId")
};
//Signature
//取出私钥并以utf8编码字节输出
var secretByte = Encoding.UTF8.GetBytes(configuration["AuthenticationDemo:SecretKeyDemo"]);
//使用非对称算法对私钥进行加密
var signingKey = new SymmetricSecurityKey(secretByte);
//使用HmacSha256来验证加密后的私钥生成数字签名
var signingCredentials = new SigningCredentials(signingKey, signingAlogorithm);
//生成Token
var Token = new JwtSecurityToken(
issuer: configuration["AuthenticationDemo:IssuerDemo"], //发布者
audience: configuration["AuthenticationDemo:AudienceDemo"], //接收者
claims: claims, //存放的用户信息
notBefore: DateTime.UtcNow, //发布时间
expires: DateTime.UtcNow.AddDays(1), //有效期设置为1天
signingCredentials //数字签名
);
//生成字符串token
var TokenStr = new JwtSecurityTokenHandler().WriteToken(Token);
return Ok(TokenStr);
}
}
}
5.运行api,可以看到生成的token
当我们把字符串复制到JWT官网,就可以是明文的,所以千万不要写账号和密码,如果要写,就再加密一层。
6.在Program.cs中注入JWT身份认证服务
里面有注释,加有跨域的问题,可以分开看。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
//取出私钥
var secretByte = Encoding.UTF8.GetBytes(builder.Configuration["AuthenticationDemo:SecretKeyDemo"]);
options.TokenValidationParameters = new TokenValidationParameters()
{
//验证发布者
ValidateIssuer = true,
ValidIssuer = builder.Configuration["AuthenticationDemo:IssuerDemo"],
//验证接收者
ValidateAudience = true,
ValidAudience = builder.Configuration["AuthenticationDemo:AudienceDemo"],
//验证是否过期
ValidateLifetime = true,
//验证私钥
IssuerSigningKey = new SymmetricSecurityKey(secretByte)
};
});
//配置跨域服务
builder.Services.AddCors(options =>
{
options.AddPolicy("cors", p =>
{
p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseCors("cors"); //跨域
app.UseHttpsRedirection();
app.UseAuthentication(); //添加jwt验证 这2句千万不能忘记了,顺序不能颠倒。
//代码从上到下执行,中间可以加判断, 权限设置问题
app.UseAuthorization();
app.MapControllers();
app.Run();
至此,获取Token的任务就完成了。
7.关键时刻,此时建立一个User类,再建立一个Login方法增加,并且增加[Authorize]。
如果在路由上面加[Authorize],那么应用于整个类的方法。
如果在HttpGet上面加[Authorize],那么应用这个方法。
无论增加哪里, 都不能访问Login了,都是401。
不加[Authorize],就是200
8.此时,使用Postman进行测试
依然是401
9.现在执行LoginToken方法,获取Token的值
10.把Token的值放在Authorization中
点击执行,就可以看到数据了。
也可以把Token的值放在Headers中,增加Authorization,还需要加bearer,后面加空格 。二选一即可。
- 给api的方法增加权限
首先在Claim这里,赋值给登录用户一个admin的用户权限,也可以使用策略。
然后在具体的方法上面,增加角色,也就是只有admin才能访问这个方法,其他用户不能访问,就是200,其他用户访问就是401,当然这是在postman里面操作的。
12.其实不用postman, 在AddSwaggerGen方法中,可以配置输入token的小锁子
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
// Register the Swagger generator, defining 1 or more Swagger documents
builder.Services.AddSwaggerGen(c =>
{
//注册到swagger中
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "Value: Bearer {token}",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header }, new List<string>()
}
});
});
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
//取出私钥
var secretByte = Encoding.UTF8.GetBytes(builder.Configuration["AuthenticationDemo:SecretKeyDemo"]);
options.TokenValidationParameters = new TokenValidationParameters()
{
//验证发布者
ValidateIssuer = true,
ValidIssuer = builder.Configuration["AuthenticationDemo:IssuerDemo"],
//验证接收者
ValidateAudience = true,
ValidAudience = builder.Configuration["AuthenticationDemo:AudienceDemo"],
//ValidateIssuerSigningKey= true,//是否验证SigningKey
//验证是否过期
ValidateLifetime = true,
//验证私钥
IssuerSigningKey = new SymmetricSecurityKey(secretByte)
};
});
//配置跨域服务
builder.Services.AddCors(options =>
{
options.AddPolicy("cors", p =>
{
p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseCors("cors"); //跨域
app.UseHttpsRedirection();
app.UseAuthentication(); //添加jwt验证 这2句千万不能忘记了,顺序不能颠倒。
//代码从上到下执行,中间可以加判断, 权限设置问题
app.UseAuthorization();
app.MapControllers();
app.Run();
13.然后启动后,就出现了,小锁子
14.此时,先点击LoginToken获取Token
再把Token输入里面去,注意加上Bearer和后面的空格,再执行Login方法就成功了。
此时,我们就可以脱离postman了。
15.后端已经全部完成了,现在做前端
前端使用vue3,只说配置即可,具体创建项目不说了,我之前也写了。
我们在axios中配置headers的Authorization。实际项目肯定不能直接写死
import axios from 'axios'
import {
ElLoading
} from 'element-plus'
//export将service传出去
export const service = axios.create({
baseURL: 'https://localhost:7193/api',
headers:{
'Authorization':'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1pbiIsIm5iZiI6MTY3MzYwMDY2MiwiZXhwIjoxNjczNjg3MDYyLCJpc3MiOiJndWxpMjEzMCIsImF1ZCI6ImF1ZGllbmNlIn0.2_EQjQzi8ZmaPoTR4hdBrePiijkk9J25nZS0KIBx6OA'
}
})
实际项目中:
肯定在登录的时候,输入账号和密码,然后访问token的接口,这个接口是不加验证的,然后把得到的token保存到localStorage中。
const Login = async () => {
await service.get(`/GetToken/LoginToken`).then(res => {
if (res.status == 200) {
console.log(1111)
//console.log(res.data)
localStorage.setItem('token', res.data);
console.log(222)
}
})
然后在axios中进行判断。
import axios from 'axios'
//export将service传出去
export const service = axios.create({
baseURL: 'http://localhost:5000/api'
})
//下面有2种写法,一种是声明函数的写法,一种是箭头函数的写法,都可以
//request interceptor 请求拦截器
service.interceptors.request.use(
function(config) {
// 在发送请求之前做些什么 Bearer
//这里是流程,如果请求的是LoginToken接口,就放过,如果不是,那么就提示没有权限
if (localStorage.getItem('token')) {
config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`
} else {
if (!config.url.includes("LoginToken")) {
alert("没有权限")
}
}
console.log('这里是请求前')
//这里是使用了element-plus,进行模态化窗体,也就是等待查询的意思,本案例在api中,设置了等待时间
return config
},
function(error) {
// 对请求错误做些什么
console.log(error)
console.log('这里是请求错误')
return Promise.reject(error)
}
)
//响应拦截器
service.interceptors.response.use(
res => {
// 在请求成功后的数据处理
if (res.status === 200) {
console.log(res.status)
console.log('这里是请求成功后')
return res;
} else {
console.log(res.status)
console.log('这里是请求失败后')
return res;
}
},
err => {
// 在响应错误的时候的逻辑处理
console.log('这里是响应错误')
return Promise.reject(err)
});
16.在界面调用
await service.get(`https://localhost:7193/api/User/Login?userId=1&pwd=1`).then(res => {
if (res.status == 200) {
console.log(1111)
console.log(res.data)
console.log(222)
}
})
17.效果
源码:
https://download.csdn.net/download/u012563853/87383701
参考:
这个是简单的认证。
.NET Core登录api时使用Basic认证_故里2130的博客-CSDN博客
版权归原作者 故里2130 所有, 如有侵权,请联系我们删除。