点击上方蓝字关注我们
JWT
JSON Web Token 经过数字签名后,无法伪造,一个能够在各方之间安全的传输JSON对象的开放标准(RFC 7519)
参考前文 [翻译]Introduction to JSON Web Tokens - 、天上月 - 博客园 (cnblogs.com)
dotnet new webapi -n SampleApi
cd SampleApi
dotnet new sln -n SampleApp
dotnet sln add .\SampleApi.csproj
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
该包已经依赖Microsoft.IdentityModel.Tokens
、System.IdentityModel.Tokens.Jwt
,该包由Azure AD 团队提供,所以不在aspnetcore6 运行时中。
或直接修改jwtaspnetcore.csproj,引用包
appsettings.json
"Authentication": {
"JwtBearer": {
"Issuer": "http://api.sampleapi.com",
"Audience": "SampleApi",
"SecurityKey": "SecurityKey23456"
}
}
Issuer:令牌的颁发者。一般就写成域名,实际可任意
Audience 颁发给谁。一般写成项目名,实际可任意
SecurityKey:签名验证的KEY;至少 128bit ,即16个英文字符以上,实际可任意英文字符
public class JwtSettings
{
public JwtSettings(byte[] key, string issuer, string audience)
{
Key = key;
Issuer = issuer;
Audience = audience;
}
///
///令牌的颁发者
///
public string Issuer { get; }
///
/// 颁发给谁
///
public string Audience { get; }
public byte[] Key { get; }
public TokenValidationParameters TokenValidationParameters => new TokenValidationParameters
{
//验证Issuer和Audience
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
//是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
ValidateLifetime = true,
ValidIssuer = Issuer,
ValidAudience = Audience,
IssuerSigningKey = new SymmetricSecurityKey(Key)
};
public static JwtSettings FromConfiguration(IConfiguration configuration)
{
var issuser = configuration["Authentication:JwtBearer:Issuer"] ?? "default_issuer";
var auidence = configuration["Authentication:JwtBearer:Audience"] ?? "default_auidence";
var securityKey = configuration["Authentication:JwtBearer:SecurityKey"] ?? "default_securitykey";
byte[] key = Encoding.ASCII.GetBytes(securityKey);
return new JwtSettings(key, issuser, auidence);
}
}
中间件Middleware引用
app.UseAuthentication();//认证
app.UseAuthorization();//授权
定义JWT扩展方法服务注入
public static IServiceCollection AddJwt(this IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton();
services.AddScoped();
var jwtSettings = JwtSettings.FromConfiguration(configuration);
services.AddSingleton(jwtSettings);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => options.TokenValidationParameters = jwtSettings.TokenValidationParameters);
return services;
}
services.AddJwt(Configuration);
定义一个数据库的实体类,数据库访问 为模拟数据
public class SysUser
{
public int Id { get; set; }
public string UserName { get; set; }
}
public interface IStorageUserService
{
///
/// 根据登录验证用户
///
///
///
Task CheckPasswordAsync(LoginInfo loginInfo);
}
public class StorageUserService : IStorageUserService
{
public async Task CheckPasswordAsync(LoginInfo loginInfo)
{
return await Task.FromResult(
new SysUser
{
Id = new Random().Next(10000),
UserName = loginInfo.UserName
}
);
}
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using SampleApi.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace SampleApi.Auth;
///
/// 登录认证个人信息
///
[ApiController]
[Route("/api/[controller]/[action]")]
[AllowAnonymous]
public class AuthController : ControllerBase
{
private readonly IStorageUserService _userService;
private readonly JwtSettings _jwtSettings;
public AuthController(JwtSettings jwtSettings, IStorageUserService userService)
{
_jwtSettings = jwtSettings;
_userService = userService;
}
///
/// 登录,生成访问Toekn
///
///
///
[HttpPost]
public async Task GenerateToken(LoginInfo loginInfo)
{
SysUser user = await _userService.CheckPasswordAsync(loginInfo);
if (user == null)
{
return Ok(new
{
Status = false,
Message = "账号或密码错误"
});
}
var claims = new List();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
var key = new SymmetricSecurityKey(_jwtSettings.Key);
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _jwtSettings.Issuer,
audience: _jwtSettings.Audience,
claims: claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: creds
);
return Ok(new
{
Status = true,
Token = new JwtSecurityTokenHandler().WriteToken(token)
});
}
}
aspnetcore6默认集成了swagger,直接运行项目,实际上为模拟数据库请求,所以点击登录接口即可。
{
"status": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6Ijc4NjciLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoic3RyaW5nIiwiZXhwIjoxNjQzMDMyNzA1LCJpc3MiOiJodHRwOi8vYXBpLnNhbXBsZWFwaS5jb20iLCJhdWQiOiJTYW1wbGVBcGkifQ.Rl8XAt2u0aZRxEJw2mVUnV6S9WzQ65qUYjqXDTneCxE"
}
当使用Swagger测试时,增加,可配置全局请求头。增加一个扩展方法。
services.AddSwagger(Configuration);
public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration)
{
services.AddSwaggerGen(options =>
{
try
{
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"), true);
}
catch (Exception ex)
{
Log.Warning(ex.Message);
}
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "SampleApp - HTTP API",
Version = "v1",
Description = "The SampleApp Microservice HTTP API. This is a Data-Driven/CRUD microservice sample"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference()
{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
}
},
Array.Empty()
}
});
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
{
Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
Name = "Authorization", //jwt默认的参数名称
In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中)
Type = SecuritySchemeType.ApiKey
});
});
services.AddEndpointsApiExplorer();
return services;
}
///
/// 编码Token
///
///
///
[HttpGet]
[AllowAnonymous]
public CurrentUser DecodeToken(string token)
{
var jwtTokenHandler = new JwtSecurityTokenHandler();
if (jwtTokenHandler.CanReadToken(token))
{
JwtPayload jwtPayload = new JwtSecurityTokenHandler().ReadJwtToken(token).Payload;
string? userIdOrNull = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.NameIdentifier)?.Value;
string? UserName = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.Name)?.Value;
CurrentUser currentUser = new CurrentUser
{
UserId = userIdOrNull == null ? null : Convert.ToInt32(userIdOrNull),
UserName = UserName
};
return currentUser;
}
return null;
}
IStorageUserService增加接口,StorageUserService的实现,创建一个CurrentUser类
public class StorageUserService : IStorageUserService
{
private readonly IHttpContextAccessor _contextAccessor;
public StorageUserService(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public async Task GetUserByRequestContext()
{
var user = _contextAccessor.HttpContext.User;
string? userIdOrNull = user.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
string? UserName = user.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
CurrentUser currentUser = new CurrentUser
{
IsAuthenticated = user.Identity.IsAuthenticated,
UserId = userIdOrNull == null ? null : Convert.ToInt32(userIdOrNull),
UserName = UserName
};
return await Task.FromResult(currentUser);
}
}
public class CurrentUser
{
///
/// 是否登录
///
public bool IsAuthenticated { get; set; }
///
/// 用户Id
///
public int? UserId { get; set; }
///
/// 用户名
///
public string? UserName { get; set; }
}
public interface IStorageUserService
{
///
/// 根据Request Header携带Authorization:Bearer+空格+AccessToken获取当前登录人信息
///
///
Task GetUserByRequestContext();
}
///
/// 根据Request Header携带Authorization:Bearer+空格+AccessToken获取当前登录人信息
///
///
[HttpGet]
[Authorize]
public async Task GetUserByRequestContext()
{
return await _userService.GetUserByRequestContext();
}
在swagger右上角,点击Authorize,header的参数结构: "Authorization: Bearer+空格+ {token}"
SampleApp/SampleApi at master · luoyunchong/SampleApp (github.com)
JSON Web Token Libraries - jwt.io 可以看到,.NET有6个类库实现了JWT。
微软 Azure团队的实现:AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet: IdentityModel extensions for .Net (github.com)
jwt-dotnet/jwt: Jwt.Net, a JWT (JSON Web Token) implementation for .NET (github.com)
其他的不多介绍
点击原文查看具体链接
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全
点个在看你最好看