- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章ASP.Net Core3.0中使用JWT认证的实现由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
JWT认证简单介绍 。
关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构.
JWT主要由三部分组成,如下:
1
|
HEADER.PAYLOAD.SIGNATURE
|
HEADER 包含token的元数据,主要是加密算法,和签名的类型,如下面的信息,说明了 。
加密的对象类型是JWT,加密算法是HMAC SHA-256 。
1
|
{
"alg"
:
"HS256"
,
"typ"
:
"JWT"
}
|
然后需要通过BASE64编码后存入token中 。
1
|
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
Payload 主要包含一些声明信息(claim),这些声明是key-value对的数据结构.
通常如用户名,角色等信息,过期日期等,因为是未加密的,所以不建议存放敏感信息.
1
|
{"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name":"admin","exp":1578645536,"iss":"webapi.cn","aud":"WebApi"}
|
也需要通过BASE64编码后存入token中 。
1
|
eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDU1MzYsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9
|
Signature jwt要符合jws(Json Web Signature)的标准生成一个最终的签名。把编码后的Header和Payload信息加在一起,然后使用一个强加密算法,如 HmacSHA256,进行加密。HS256(BASE64(Header).Base64(Payload),secret) 。
1
|
2_akEH40LR2QWekgjm8Tt3lesSbKtDethmJMo_3jpF4
|
最后生成的token如下 。
1
|
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDU1MzYsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9.2_akEH40LR2QWekgjm8Tt3lesSbKtDethmJMo_3jpF4
|
开发环境 。
框架:asp.net 3.1 。
IDE:VS2019 。
ASP.NET 3.1 Webapi中使用JWT认证 。
命令行中执行执行以下命令,创建webapix项目:
1
|
dotnet
new
webapi -n Webapi -o WebApi
|
特别注意的时,3.x默认是没有jwt的Microsoft.AspNetCore.Authentication.JwtBearer库的,所以需要手动添加NuGet Package,切换到项目所在目录,执行 .net cli命令 。
1
|
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.0
|
创建一个简单的POCO类,用来存储签发或者验证jwt时用到的信息 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
using
Newtonsoft.Json;
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Threading.Tasks;
namespace
Webapi.Models
{
public
class
TokenManagement
{
[JsonProperty(
"secret"
)]
public
string
Secret {
get
;
set
; }
[JsonProperty(
"issuer"
)]
public
string
Issuer {
get
;
set
; }
[JsonProperty(
"audience"
)]
public
string
Audience {
get
;
set
; }
[JsonProperty(
"accessExpiration"
)]
public
int
AccessExpiration {
get
;
set
; }
[JsonProperty(
"refreshExpiration"
)]
public
int
RefreshExpiration {
get
;
set
; }
}
}
|
然后在 appsettings.Development.json 增加jwt使用到的配置信息(如果是生成环境在 appsettings.json 添加即可) 。
1
2
3
4
5
6
7
|
"tokenManagement"
: {
"secret"
:
"123456"
,
"issuer"
:
"webapi.cn"
,
"audience"
:
"WebApi"
,
"accessExpiration"
: 30,
"refreshExpiration"
: 60
}
|
然后再startup类的ConfigureServices方法中增加读取配置信息 。
1
2
3
4
5
6
7
|
public
void
ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure<TokenManagement>(Configuration.GetSection(
"tokenManagement"
));
var token = Configuration.GetSection(
"tokenManagement"
).Get<TokenManagement>();
}
|
到目前为止,我们完成了一些基础工作,下面再webapi中注入jwt的验证服务,并在中间件管道中启用authentication中间件.
startup类中要引用jwt验证服务的命名空间 。
1
2
|
using
Microsoft.AspNetCore.Authentication.JwtBearer;
using
Microsoft.IdentityModel.Tokens;
|
然后在 ConfigureServices 方法中添加如下逻辑 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata =
false
;
x.SaveToken =
true
;
x.TokenValidationParameters =
new
TokenValidationParameters
{
ValidateIssuerSigningKey =
true
,
IssuerSigningKey =
new
SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Secret)),
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ValidateIssuer =
false
,
ValidateAudience =
false
};
});
|
再 Configure 方法中启用验证 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
void
Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if
(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
|
上面完成了JWT验证的功能,下面就需要增加签发token的逻辑。我们需要增加一个专门用来用户认证和签发token的控制器,命名成 AuthenticationController ,同时增加一个请求的DTO类 。
1
2
3
4
5
6
7
8
9
10
11
|
public
class
LoginRequestDTO
{
[Required]
[JsonProperty(
"username"
)]
public
string
Username {
get
;
set
; }
[Required]
[JsonProperty(
"password"
)]
public
string
Password {
get
;
set
; }
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[Route(
"api/[controller]"
)]
[ApiController]
public
class
AuthenticationController : ControllerBase
{
[AllowAnonymous]
[HttpPost, Route(
"requestToken"
)]
public
ActionResult RequestToken([FromBody] LoginRequestDTO request)
{
if
(!ModelState.IsValid)
{
return
BadRequest(
"Invalid Request"
);
}
return
Ok();
}
}
|
目前上面的控制器只实现了基本的逻辑,下面我们要创建签发token的服务,去完成具体的业务。第一步我们先创建对应的服务接口,命名为 IAuthenticateService 。
1
2
3
4
|
public
interface
IAuthenticateService
{
bool
IsAuthenticated(LoginRequestDTO request,
out
string
token);
}
|
接下来,实现接口 。
1
2
3
4
5
6
7
|
public
class
TokenAuthenticationService : IAuthenticateService
{
public
bool
IsAuthenticated(LoginRequestDTO request,
out
string
token)
{
throw
new
NotImplementedException();
}
}
|
在 Startup 的 ConfigureServices 方法中注册服务 。
1
|
services.AddScoped<IAuthenticateService, TokenAuthenticationService>();
|
在Controller中注入IAuthenticateService服务,并完善action 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
AuthenticationController : ControllerBase
{
private
readonly
IAuthenticateService _authService;
public
AuthenticationController(IAuthenticateService authService)
{
this
._authService = authService;
}
[AllowAnonymous]
[HttpPost, Route(
"requestToken"
)]
public
ActionResult RequestToken([FromBody] LoginRequestDTO request)
{
if
(!ModelState.IsValid)
{
return
BadRequest(
"Invalid Request"
);
}
string
token;
if
(_authService.IsAuthenticated(request,
out
token))
{
return
Ok(token);
}
return
BadRequest(
"Invalid Request"
);
}
}
|
正常情况,我们都会根据请求的用户和密码去验证用户是否合法,需要连接到数据库获取数据进行校验,我们这里为了方便,假设任何请求的用户都是合法的.
这里单独加个用户管理的服务,不在IAuthenticateService这个服务里面添加相应逻辑,主要遵循了 职责单一原则 。首先和上面一样,创建一个服务接口 IUserService 。
1
2
3
4
|
public
interface
IUserService
{
bool
IsValid(LoginRequestDTO req);
}
|
实现 IUserService 接口 。
1
2
3
4
5
6
7
8
|
public
class
UserService : IUserService
{
//模拟测试,默认都是人为验证有效
public
bool
IsValid(LoginRequestDTO req)
{
return
true
;
}
}
|
同样注册到容器中 。
1
|
services.AddScoped<IUserService, UserService>();
|
接下来,就要完善TokenAuthenticationService签发token的逻辑,首先要注入IUserService 和 TokenManagement,然后实现具体的业务逻辑,这个token的生成还是使用的Jwt的类库提供的api,具体不详细描述.
特别注意下TokenManagement的注入是已IOptions的接口类型注入的,还记得在Startpup中吗?我们是通过配置项的方式注册TokenManagement类型的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public
class
TokenAuthenticationService : IAuthenticateService
{
private
readonly
IUserService _userService;
private
readonly
TokenManagement _tokenManagement;
public
TokenAuthenticationService(IUserService userService, IOptions<TokenManagement> tokenManagement)
{
_userService = userService;
_tokenManagement = tokenManagement.Value;
}
public
bool
IsAuthenticated(LoginRequestDTO request,
out
string
token)
{
token =
string
.Empty;
if
(!_userService.IsValid(request))
return
false
;
var claims =
new
[]
{
new
Claim(ClaimTypes.Name,request.Username)
};
var key =
new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));
var credentials =
new
SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var jwtToken =
new
JwtSecurityToken(_tokenManagement.Issuer, _tokenManagement.Audience, claims, expires: DateTime.Now.AddMinutes(_tokenManagement.AccessExpiration), signingCredentials: credentials);
token =
new
JwtSecurityTokenHandler().WriteToken(jwtToken);
return
true
;
}
}
|
准备好测试试用的APi,打上Authorize特性,表明需要授权! 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
[ApiController]
[Route(
"[controller]"
)]
[Authorize]
public
class
WeatherForecastController : ControllerBase
{
private
static
readonly
string
[] Summaries =
new
[]
{
"Freezing"
,
"Bracing"
,
"Chilly"
,
"Cool"
,
"Mild"
,
"Warm"
,
"Balmy"
,
"Hot"
,
"Sweltering"
,
"Scorching"
};
private
readonly
ILogger<WeatherForecastController> _logger;
public
WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public
IEnumerable<WeatherForecast> Get()
{
var rng =
new
Random();
return
Enumerable.Range(1, 5).Select(index =>
new
WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
|
支持我们可以测试验证了,我们可以使用postman来进行http请求,先启动http服务,获取url,先测试一个访问需要授权的接口,但没有携带token信息,返回是401,表示未授权 。
下面我们先通过认证接口,获取token,居然报错,查询了下,发现HS256算法的秘钥长度最新为128位,转换成字符至少16字符,之前设置的秘钥是123456,所以导致异常.
1
|
System.ArgumentOutOfRangeException: IDX10603: Decryption failed. Keys tried: 'HS256'. Exceptions caught: '128'. token: '48' (Parameter 'KeySize') at
|
更新秘钥 。
1
2
3
4
5
6
7
|
"tokenManagement"
: {
"secret"
:
"123456123456123456"
,
"issuer"
:
"webapi.cn"
,
"audience"
:
"WebApi"
,
"accessExpiration"
: 30,
"refreshExpiration"
: 60
}
|
重新发起请求,成功获取token 。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJleHAiOjE1Nzg2NDUyMDMsImlzcyI6IndlYmFwaS5jbiIsImF1ZCI6IldlYkFwaSJ9.AehD8WTAnEtklof2OJsvg0U4_o8_SjdxmwUjzAiuI-o 。
把token带到之前请求的api中,重新测试,成功获取数据 。
基于token的认证方式,让我们构建分布式/松耦合的系统更加容易。任何地方生成的token,只有拥有相同秘钥,就可以再任何地方进行签名校验.
当然要用好jwt认证方式,还有其他安全细节需要处理,比如palyload中不能存放敏感信息,使用https的加密传输方式等等,可以根据业务实际需要再进一步安全加固! 。
同时我们也发现使用token,就可以摆脱cookie的限制,所以JWT是移动app开发的首选! 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://www.cnblogs.com/liuww/p/12177272.html 。
最后此篇关于ASP.Net Core3.0中使用JWT认证的实现的文章就讲到这里了,如果你想了解更多关于ASP.Net Core3.0中使用JWT认证的实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!