ASP.NET Core Web API用户身份验证
一、JWT介绍
ASP.NET Core Web API用户身份验证的方法有很多,本文只介绍JWT方法。JWT实现了服务端无状态,在分布式服务、会话一致性、单点登录等方面凸显优势,不占用服务端资源。简单来说,JWT的验证过程如下所示:
(1)通过用户名和密码获取一个Token。
(2)访问API时,加上这个Token。
Token包含过期时间、用户角色等信息,可以在多种场合灵活使用。
二、基本认证
2.1 场景描述
在基本认证的场景中,我们假设有一个Controller,代码如下所示:
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{[HttpGet]public string Get(){return "success";}
}
这个Controller非常简单,就是访问之后返回"success"这个字符串。
现在,我们希望用户登录之后(提供用户名和密码)才能使用此API。
2.2 开发步骤
1、在NuGet中添加Microsoft.AspNetCore.Authentication.JwtBearer。
2、在Program.cs中,对builder.Services添加认证服务:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>{opt.TokenValidationParameters = new TokenValidationParameters(){ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = false,ValidateIssuerSigningKey = false};});
在上面的参数中,可以根据使用场景进行灵活配置,这个后面会介绍。在此,使用最简单的配置。
3、同样在Program.cs中,添加以下语句:
app.UseAuthentication();
需要注意的是,此句需要在页面路由之前,例如是app.UseHttpsRedirection();之前,如下所示:
app.UseAuthentication();app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();
4、在需要认证的Controller或某个具体方法上加上[Authorize]标记。例如我们在一开始介绍的API上加上标记:
[Authorize]
[HttpGet]
public string Get()
{return "success";
}
此时,如果再去访问此API,就会返回401没有权限的错误。
5、创建登录的Controller,也就是通过用户名和密码获取Token。
[Route("api/auth")]
[ApiController]
public class AuthController : ControllerBase
{[HttpPost]public string Gettoken(string username, string password){if (username == "admin" && password == "123456"){var claims = new[]{new Claim(ClaimTypes.Name, username)};var jwttoken = new JwtSecurityToken(claims: claims);var token = new JwtSecurityTokenHandler().WriteToken(jwttoken);return token;}return "用户不存在或密码错误";}
}
上面的用户认证简单的做了字符串比对,实际上可以通过查数据库的方法验证用户是否合法。
至此,用户验证的后端就开发完成了。
三、前端访问API
3.1 通过Swagger测试
很多时候,我们使用Swagger来测试API,但默认的Swagger配置没有用户验证,需要进行添加。
打开Program.cs,把builder.Services.AddSwaggerGen();这一句修改为:
builder.Services.AddSwaggerGen(c =>
{c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme(){In = ParameterLocation.Header,Type = SecuritySchemeType.ApiKey,Description = "Bearer Token",Name = "Authorization",BearerFormat = "JWT",Scheme = "Bearer"});c.AddSecurityRequirement(new OpenApiSecurityRequirement() {{new OpenApiSecurityScheme(){Reference=new OpenApiReference(){Type=ReferenceType.SecurityScheme,Id="Bearer"}},new string[]{ }}});
});
此时,打开Swagger,就会看到右上角有一个Authorize的按钮,如下图所示:
点击按钮,会要求输入一个Token。我们从上面写的登录Controller(AuthController)获取。如下图所示:
最下面的响应字符串就是我们要的Token。把这个Token填入到上面弹出的对话框中,注意需要在字符串前加上“Bearer ”。如下图所示:
此时,再去访问TestController,就会返回成功结果。
3.2 前端访问方法
在无用户验证要求的时候,前端访问TestController的代码如下所示:
fetch("https://localhost:28911/test", {method: "GET"
}).then(resp => {return resp.text();
}).then(data => {console.log(data);
}).catch(err => {console.log(err)
});
API前加上[Authorize]之后,上述调用也会返回401错误。上述调用需要把Token加入到Header中。
fetch("https://localhost:28911/test", {method: "GET",headers: {"Authorization": "Bearer eyJhbGciOiJ...太长,Token后面省略"}
}).then(resp => {return resp.text();
}).then(data => {console.log(data);
}).catch(err => {console.log(err)
});
此时,即可再次成功获取结果。
四、常见用户身份验证场景
4.1 Token有效期
一般情况下,通过用户名和密码得到了Token之后,我们不希望这个Token是永久有效的。也就是说,过了一段时间之后,Token失效,用户需要重新登录。
需要增加有效期,有几处地方需要修改。
首先是Program.cs中,原来的配置如下所示:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>{opt.TokenValidationParameters = new TokenValidationParameters(){ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = false,ValidateIssuerSigningKey = false};});
需要把ValidateLifetime改为true:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>{opt.TokenValidationParameters = new TokenValidationParameters(){ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = true,ClockSkew = TimeSpan.FromSeconds(30),};});
然后在AuthController的Gettoken方法里,加上有效期:
var claims = new[]{new Claim(JwtRegisteredClaimNames.Nbf,new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()) ,new Claim(JwtRegisteredClaimNames.Exp,new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds().ToString()),new Claim(ClaimTypes.Name, username)
};
上面配置的有效期是30分钟。
至此,当获得一个新的Token之后,经过30分钟,这个Token就无法使用了。
4.2 第三方验证
很多网站上提供QQ登录、微信登录、微博登录等功能,我们以微信登录进行说明。如果我们需要使用微信登录,需要到微信开发者平台注册,拿到一个叫AppKey的东西。这个AppKey相当于一个私钥,是不能让别人看到的。因为我们要使用微信的登录验证服务,这个服务不能向任何人提供,而且需要区分是哪个第三方在使用服务。
为了实现上述功能,认证时加入了一个IssUser的概念,也就是哪些APP可以调用服务。
在Program.cs中,修改配置:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>{opt.TokenValidationParameters = new TokenValidationParameters(){ValidateIssuer = true,ValidateAudience = false,ValidateLifetime = false,ValidateIssuerSigningKey = true,ValidIssuer = "App名称",IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("App私钥"))};});
然后,在Gettoken时,进行修改:
var claims = new[]{new Claim(ClaimTypes.Name, username)
};
var m5dkey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("App私钥"));
var creds = new SigningCredentials(m5dkey, SecurityAlgorithms.HmacSha256);
var jwttoken = new JwtSecurityToken(issuer: "App名称",claims: claims,expires: DateTime.Now.AddMinutes(30),signingCredentials: creds
);
var token = new JwtSecurityTokenHandler().WriteToken(jwttoken);
return token;
4.3 角色或权限
很多时候,用户登录之后,并不是可以访问所有的API。用户可以分出不同的角色,不同的角色可以访问不同的资源。
要做到这一点,首先在Gettoken时,把用户的角色加入到Token中。
var claims = new[]{new Claim(ClaimTypes.Name, username),new Claim("Role", "admin")
};
然后,在API前,指明此资源需要什么角色。
[Authorize(Roles = "admin")]
[HttpGet]
public string Get()
{return "success";
}
这样,按角色分配资源的功能就完成了。
相关文章:

ASP.NET Core Web API用户身份验证
一、JWT介绍 ASP.NET Core Web API用户身份验证的方法有很多,本文只介绍JWT方法。JWT实现了服务端无状态,在分布式服务、会话一致性、单点登录等方面凸显优势,不占用服务端资源。简单来说,JWT的验证过程如下所示: &a…...
785. 快速排序
785. 快速排序 给定你一个长度为 n n n 的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行,第一行包含整数 n n n。 第二行包含 n n n 个整数(所有整数均在 1 ∼ 1 0 9 1 \th…...
C6678学习-IPC
文章目录 1、简介2、模块MultiProc静态设置(cfg设置)动态设置 IPCNotifyMessageQShareRegion 1、简介 IPC: Inter-Processor Communication 处理器间通信,指提供多处理器环境中的处理器之间的通信、相同处理器不同线程间的通信。包括数据传递…...

利用 Delte-Sigma ADC简化电路设计
很多时候在电路中选择合适的 ADC可以很大程度上简化前端的电路。这里我们一起来看一个电阻电桥的例子: 这里用到了一只仪表放大器和一只运算放大器,他们实际上主要完成了三个功能: 1. 抑制了 2.5V的共模信号; 2. 将-1…...

如何在 Windows 11 启用 Hyper-V
准备在本机玩一下k8s,需要先启用 Hyper-V,谁知道这一打开,没有 Hyper-V选项: 1、查看功能截图: 2、以下文件保存记事本,然后重命名为*.bat pushd "%~dp0" dir /b %SystemRoot%\servicing\Packa…...

哈希表企业应用-DNA的字符串检测
DNA的字符串检测-引言 若干年后, ikun DNA 检测部成立,专门对 这些ikun的解析检测 突然发现已经完全控制不了 因为学生已经会了 而且是太会了 所以DNA采用 以下视频测试: ikun必进曲 ikun必经曲 ikun必阶曲 如何感受到了吧!,如果你现在唱跳并且还Rap 还有打篮球 还有铁山靠 那…...
Kafka运维与监控
Kafka运维与监控 Kafka运维与监控一、简介二、运维1.安装和部署安装部署 2.优化参数配置配置文件高级配置分区和副本设置分区数量设置副本数量设置 网络参数调优传输机制设置连接数和缓冲区大小设置 消息压缩和传输设置消息压缩设置消息传输设置 磁盘设置和文件系统分区磁盘容量…...

【Redis—哨兵机制】
文章目录 概念哨兵机制如何工作的监控(如何判断主节点真的故障了)哪个哨兵进行主从故障转移?故障转移流程哨兵集群 概念 当进行主从复制时,如果主节点挂掉了,那么没有主节点来服务客户端的写操作请求了,也…...

MySQL学习笔记第七天
第07章单行函数 2. 数值函数 2.4 指数函数、对数函数 函数用法POW(x,y),POWER(X,Y)返回x的y次方EXP(X)返回e的x次方,其中e是一个常数,2.718281828459045LN(X),LOG(X)返回以e为底的X的对数,当x<0时,返…...

中级软件设计师备考---程序设计语言和法律法规知识
目录 需要掌握的程序语言特点法律法规知识---保护期限法律法规知识---知识产权人确定法律法规知识---侵权判定标准化基础知识 需要掌握的程序语言特点 Fortran语言:科学计算、执行效率高Pascal语言:为教学而开发的、表达能力强,演化出了Delp…...

Leetcode434. 字符串中的单词数
Every day a leetcode 题目来源:434. 字符串中的单词数 解法1:istringstream 我们知道,C默认通过空格(或回车)来分割字符串输入,即区分不同的字符串输入。 istringstream类用于执行C风格的串流的输入操…...
C++ cmake工程引入qt6和Quick 教程
目录标题 前言QML简介锻炼C水平 cmake修改方法方式一(qt6_add_resources)方式二 (qt_add_qml_module ) 其他相关知识为什么会有_other_files?qt_standard_project_setup() 函数qt_add_qml_module() 和 qt6_add_resources()的方式差异const QU…...

JavaEE - 网络编程
一、网络编程基础 为什么需要网络编程? 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是网络。 相比本…...

【Android车载系列】第11章 系统服务-SystemServer自定义服务
1 编写自定义系统服务 1.1 AIDL接口定义 系统源码目录/frameworks/base/core/java/android/app/下新建AIDL接口IYvanManager.aidl package android.app;/** * 目录:/frameworks/base/core/java/android/app/IYvanManager.aidl */ interface IYvanManager{String …...
Lerna
Lerna Lerna是一个优化基于gitnpm的多pagkage项目的管理工具 解决的痛点 痛点一:重复操作 多Package本地link多Package依赖安装多Package单元测试多Package代码提交多Package代码发布 痛点二:版本一致性 发布时版本一 致性发布后相互依赖版本升级 package越多,管…...
迁移学习 pytorch
迁移学习(Transfer Learning)是通过使用一个预训练模型来快速训练一个新的网络模型,通常应用于数据集较小或计算资源较少的情况下。在 PyTorch 中,由于 torchvision 库中已经内置了一些经典的预训练模型,因此我们可以通过简单的调用函数来实现迁移学习。 下面是一个基于 …...

【python】keras包:深度学习( RNN循环神经网络 Recurrent Neural Networks)
RNN循环神经网络 应用: 物体移动位置预测、股价预测、序列文本生成、语言翻译、从语句中自动识别人名、 问题总结 这类问题,都需要通过历史数据,对未来数据进行预判 序列模型 两大特点 输入(输出)元素具有顺序关系…...

vue框架快速入门
vue 1、第一个Vue程序1.1、什么是Vue程序1.2、为什么要使用MVVM1.3、Vue1.4、第一个vue程序 2、基础语法2.1、v-bind2.2、v-if, v-else2.3、v-for2.4、v-on 3、Vue表单双绑、组件3.1、什么是双向数据绑定3.2、在表单中使用双向数据绑定3.3、什么是组件 4、Axios异步…...

Java连接顺丰开放平台
今天使用Java去访问顺丰的开放平台时,JSON转换一直不成功,最终发现是 可以看到这里是 "apiResultData": "{\"success\": .........它是以 " 开头的!!!如果是对象的话,那么…...

前端三剑客 - HTML
前言 前面都是一些基础的铺垫,现在就正式进入到web开发环节了。 我们的目标就是通过学习 JavaEE初阶,搭建出一个网站出来。 一个网站分成两个部分: 前端(客户端) 后端(服务器) 通常这里的客户端…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...