ASP.NET Core 3.1中使用JWT身份认证

Jonny Lin 2020-04-06 14:28:32 3419 收藏 11
分类专栏: asp.net core 文章标签: JWT Authentication Authorization ASP.NET Core
版权
文章目录
0、引言
1、关于Authentication与Authorization
2、整个认证流程是怎样的?
3、开始JWT身份认证
3.1 安装JwtBearer包
3.2 安装Swashbuckle.AspNetCore包
3.3 添加身份认证相关服务到容器中
3.4 添加Swagger服务到容器中
3.5 将身份认证加入到管道中
3.6 将swagger加入到管道中
3.7 在需要授权的资源上加入Authorize
4 、测试
4.1 请求资源
4.2 调用登录获取token
4.3 将token添加到Header中
4.4 再次请求
4.5 切换admin账户登录
5、登录逻辑代码
0、引言
若不清楚什么是JWT的请先了解下什么是JWT。

1、关于Authentication与Authorization
我相信在aspnet core中刚接触甚至用了段时间这两个概念的时候都是一头雾水的,傻傻分不清。
认证(Authentication)和授权(Authorization)在概念上比较的相似,且又有一定的联系,因此很容易混淆。
认证(Authentication)是指验证用户身份的过程,即当用户要访问受保护的资源时,将其信息(如用户名和密码)发送给服务器并由服务器验证的过程。
授权(Authorization)是验证一个已通过身份认证的用户是否有权限做某件事情的过程。
有过RBAC的开发经验者来说这里可以这么通俗的来理解:认证是验证一个用户是否“合法”(一般就是检查数据库中是否有这么个用户),授权是验证这个用户是否有做事情的权限(简单理解成RBAC中的用户权限)。

2、整个认证流程是怎样的?

从图中可以看到整个认证、授权的流程,先进行身份验证 ,验证通过后将Token放回给客户端,客户端访问资源的时候请求头中添加Token信息,服务器进行验证并于授权是否能够访问该资源。

3、开始JWT身份认证
3.1 安装JwtBearer包
在.csproj项目中添加JWT包(这里添加有很多种方式,自行选择)

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
1
3.2 安装Swashbuckle.AspNetCore包
这里便于进行测试,引入Swagger工具。

<PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.1" />
1
3.3 添加身份认证相关服务到容器中
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = "jonny",
ValidAudience = "jonny",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretsecretsecret"))
};
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
说明

配置项 类型 说明
ValidateIssuerSigningKey bool 是否调用对签名securityToken的SecurityKey进行验证。
ValidIssuer string 将用于检查令牌的发行者是否与此发行者相同。
ValidateIssuer bool 是否验证发行者
ValidAudience string 检查令牌的受众群体是否与此受众群体相同。
ValidateAudience bool 在令牌验证期间验证受众 。
ValidateLifetime bool 验证生命周期。
3.4 添加Swagger服务到容器中
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("openapi", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "统一身份认证API",
Description = "身份认证和授权详解",
Version = "v1"
});
var scheme = new OpenApiSecurityScheme()
{
Scheme = JwtBearerDefaults.AuthenticationScheme,
BearerFormat = "JWT",
In = ParameterLocation.Header,
//头名称
Name = ApiKeyConstants.HeaderName,
Type = SecuritySchemeType.ApiKey,
Description = "Bearer Token"
};
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, scheme);
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
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
31
32
33
34
aspnet core 3.x swagger与2.x有细微的差别,例如swagger中加入jwt和以前就有一定的差别。

swagger加入身份认证后出现了认证按钮。


3.5 将身份认证加入到管道中
//身份认证中间件(踩坑:授权中间件必须在认证中间件之前)
app.UseAuthentication();
1
2
3.x中身份认证一定要在UseRouting和UseEndpoints之间

3.6 将swagger加入到管道中
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.RoutePrefix = string.Empty;
//配置swagger端点
options.SwaggerEndpoint("swagger/openapi/swagger.json", "openapi v1");
});
1
2
3
4
5
6
7
3.7 在需要授权的资源上加入Authorize
例如:

[HttpGet("role")]
[Authorize(Roles = "admin")]
public IEnumerable<Claim> GetRole()
{
return HttpContext.User.FindAll(c => c.Type == ClaimTypes.Role);
}
1
2
3
4
5
6
这里默认使用角色授权机制

4 、测试
4.1 请求资源
这时会返回401,因为没有进行身份认证


4.2 调用登录获取token


4.3 将token添加到Header中


4.4 再次请求
这时返回403,是因为使用的jonny账户登录的没有admin权限。


4.5 切换admin账户登录

重复上面的4.3、4.4步骤 。再次测试。这时就能正常访问。


5、登录逻辑代码
我这里就不做过多的解释 ,直接将相关创建JTW代码等贴出来。

public interface ICustomAuthenticationManager
{
string Authenticate(string username, string password);

IDictionary<string, string> Tokens { get; }
}
public class CustomAuthenticationManager : ICustomAuthenticationManager
{
private readonly IDictionary<string, string> users = new Dictionary<string, string>
{
{ "admin", "admin" },
{ "jonny", "jonny" },
{ "xhl", "xhl" },
{ "james", "james" }
};

public IDictionary<string, string> Tokens { get; } = new Dictionary<string, string>();

public string Authenticate(string username, string password)
{
var claimsIdentity = new ClaimsIdentity(new[]{
new Claim(ClaimTypes.Name,username)
});
if (!users.Any(u => u.Key == username && u.Value == password))
{
return null;
}
if (username == "admin")
{
claimsIdentity.AddClaims(new[]
{
new Claim( ClaimTypes.Email, "xhl.jonny@gmail.com"),
new Claim( "ManageId", "admin"),
new Claim(ClaimTypes.Role,"admin")
});
}
var handler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = claimsIdentity,
Expires = DateTime.Now.AddMinutes(3),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretsecretsecret")), SecurityAlgorithms.HmacSha256),
};
var securityToken = handler.CreateToken(tokenDescriptor);
var token = handler.WriteToken(securityToken);
Tokens.Add(token, username);
return token;
}
}


上面使用内存数据进行逻辑验证 ,实际中需要使用数据库查询验证等。

今天的JWT身份认证就介绍完了 ,下一篇文章将介绍授权。角色授权、身份授权(Claim)、自定义策略授权。
————————————————