1、建.NetCore的WebApi项目,安装包IdentityModel,Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.AspNetCore.Authorization
2、注册服务和中间件
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;
using System.Threading.Tasks;
namespace WebApiJwt.Utils
{
public static class AuthorizationSetup
{
public static void AddAuthorizationSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
// 策略
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy => policy.RequireRole("Admin", "System"));
});
//读取配置文件
var symmetricKeyAsBase64 = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
var signingKey = new SymmetricSecurityKey(keyByteArray);
var Issuer = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
var Audience = ConfigHelper.GetSectionValue("JwtSetting:Audience");
// 令牌验证参数
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据,不安全
IssuerSigningKey = signingKey,//解密的密钥
ValidateIssuer = true,//是否验证发行人,就是验证载荷中的Iss是否对应ValidIssuer参数
ValidIssuer = Issuer,//发行人
ValidateAudience = true,//是否验证订阅人,就是验证载荷中的Aud是否对应ValidAudience参数
ValidAudience = Audience,//订阅人
ValidateLifetime = true,//是否验证过期时间,过期了就拒绝访问
ClockSkew = TimeSpan.Zero,//缓冲过期时间,真正过期时间=配置过期时间+缓冲过期时间,默认5分钟
RequireExpirationTime = true,//token需要设置过期时间
};
// 开启Bearer认证,添加JwtBearer服务
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.TokenValidationParameters = tokenValidationParameters;
o.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
// 如果过期,则把<是否过期>添加到,返回头信息中
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
}
}
}
Startup.cs
注册服务:services.AddAuthorizationSetup();
添加中间件:app.UseAuthentication(); app.UseAuthorization();
3、生成Token
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using WebApiJwt.Models;
namespace WebApiJwt.Utils
{
public class JwtHelper
{
/// <summary>
/// 颁发JWT字符串
/// </summary>
/// <param name="tokenModel"></param>
/// <returns></returns>
public static object IssueJwt(TokenModel tokenModel)
{
DateTime authTime = DateTime.UtcNow;
string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");//颁发者
string aud = ConfigHelper.GetSectionValue("JwtSetting:Audience");//可以给哪些客户端使用
string secret = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");//加密的Key
//token有效期 分钟
DateTime expiresAt = authTime.AddMinutes(Convert.ToDouble(ConfigHelper.GetSectionValue("JwtSetting:ExpireMinutes")));
//设置Claim
var claims = new List<Claim>
{
//claim默认配置
new Claim(JwtRegisteredClaimNames.Jti, tokenModel.UserId.ToString()),
new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"),
new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}") ,
//过期时间,JWT有缓冲过期时间,所以过期时间到了会延迟一会儿再过期,影响不大。
new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expiresAt).ToUnixTimeSeconds()}"),
new Claim(ClaimTypes.Expiration, expiresAt.ToString()),
new Claim(JwtRegisteredClaimNames.Iss,iss),//颁发者
new Claim(JwtRegisteredClaimNames.Aud,aud),//可以给哪些客户端使用
new Claim(ClaimTypes.Name, tokenModel.UserName),
new Claim(ClaimTypes.Email, tokenModel.Email)
};
//设置Claim角色
claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
//秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var jwtSecurityToken = new JwtSecurityToken(issuer: iss, claims: claims, signingCredentials: creds);
var jwtHandler = new JwtSecurityTokenHandler();
var encodedJwt = jwtHandler.WriteToken(jwtSecurityToken);
//存储 Token 信息
var jwt = new
{
UserId = tokenModel.UserId,
Token = encodedJwt,
Auths = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
Expires = new DateTimeOffset(expiresAt).ToUnixTimeSeconds(),
Success = true
};
return jwt;
}
/// <summary>
/// 解析
/// </summary>
/// <param name="jwtStr"></param>
/// <returns></returns>
public static TokenModel SerializeJwt(string jwtStr)
{
var jwtHandler = new JwtSecurityTokenHandler();
if (!jwtHandler.CanReadToken(jwtStr)) { return null; }
string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
if (jwtToken.Issuer != iss)
{
return null;//不正确
}
if (jwtToken.ValidTo < DateTime.UtcNow)
{
return null;//过期
}
object role, userName, email;
try
{
jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
jwtToken.Payload.TryGetValue(ClaimTypes.Name, out userName);
jwtToken.Payload.TryGetValue(ClaimTypes.Email, out email);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
var tm = new TokenModel
{
UserId = jwtToken.Id.ToString(),
Role = role != null ? role.ToString() : "",
UserName = userName != null ? userName.ToString() : "",
Email = email != null ? email.ToString() : ""
};
return tm;
}
}
}
配置
"JwtSetting": {
"Issuer": "jwtIssuer", //颁发者
"Audience": "jwtAudience", //可以给哪些客户端使用
"SecretKey": "abcdabcdabcdabcdabcdabcdabcdabcd", //加密的Key,长度最少要32位,不然报错。
"ExpireMinutes": "3" //token有效期3分钟
}
辅助
using Microsoft.Extensions.Configuration;
using System;
namespace WebApiJwt.Utils
{
public class ConfigHelper
{
public readonly static IConfiguration configuration;
static ConfigHelper()
{
configuration = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json", true, true)
.AddInMemoryCollection()
.Build();
}
public static string GetSectionValue(string key)
{
return configuration[key];
}
public static string connectionString
{
get { return configuration["ConnectionStrings:Default"]; }
}
}
}
4、ApiController
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using WebApiJwt.Models;
using WebApiJwt.Utils;
namespace WebApiJwt.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class AuthorizeController : ControllerBase
{
/// <summary>
/// 生成令牌
/// </summary>
/// <returns></returns>
[HttpGet]
public string GenToken()
{
TokenModel tokenModel = new TokenModel { UserId = "1001", Role = "Admin", Email = "908085411@qq.com", UserName = "邢帅杰" };
string jwtToken = JsonConvert.SerializeObject(JwtHelper.IssueJwt(tokenModel));
return jwtToken;
}
/// <summary>
/// 需要Admin权限
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(Roles = "Admin")]
//[Authorize(Policy = "Admin")]//使用策略来映射多个角色
public IActionResult Admin()
{
return Ok("admin........");
}
/// <summary>
/// 解析Token
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public IActionResult AnalysisToken()
{
var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
var user = JwtHelper.SerializeJwt(tokenHeader);
return Ok(user);
}
}
}
5、 生成:https://localhost:44393/api/Authorize/GenToken,解析:https://localhost:44393/api/Authorize/AnalysisToken,在header中添加 Authorization:Bearer token
参考:
https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/weixin_42045719/article/details/91973878
http://cn.voidcc.com/question/p-vckjdtzx-hv.html
https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/baidu_35726140/article/details/84867520
https://www.cnblogs.com/xwc1996/p/14058115.html
浙公网安备 33010602011771号