ASP.NET Core生成,校驗jwt的(accessToken)訪問令牌和(refreshToken)刷新令牌示例講解
-懶狗如我,解析都寫到注釋里了,寫的很詳細,不懂的地方翻翻文檔
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using jwt.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
namespace jwtTest.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class SignInController : Controller
{
private IConfiguration _configuration { get; set; }
// 控制器注入Configuration依賴,方便獲取appsettinfs.json中的SecurityKey
public SignInController(IConfiguration config)
{
_configuration = config;
}
[HttpGet("login")]
public ActionResult Login(string username, string password)//應該寫個LoginDto,我懶了
{
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
{
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
//在此進行賬號密碼認證,此代碼省略
//------------生成AccessToken----------------------------------
// token中的claims用於儲存自定義信息,如登錄之后的用戶id等
var claims = new[]
{
new Claim("username",username),
new Claim("password",password),//演示用,(不要把密碼寫進token啊喂!!!(#`O′))
//new Claim(ClaimTypes.Role,"admin")
new Claim("role","admin")//此寫法和上面寫法效果一樣
};
// 獲取SecurityKey
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"));
//生成Token
var token = new JwtSecurityToken(
issuer: "cxy", // 發布者
audience: "myClient", // 接收者
notBefore: DateTime.Now, // token簽發時間
expires: DateTime.Now.AddMinutes(30), // token過期時間
claims: claims, // 該token內存儲的自定義字段信息
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用於簽發token的秘鑰算法
);
//-----------下面是生成RefreshToken--------------------------
var refClaims = new[]
{
new Claim("role","refresh")
};
var refreshToken = new JwtSecurityToken(
issuer: "cxy", // 發布者
audience: "myClient", // 接收者
notBefore: DateTime.Now, // token簽發時間
expires: DateTime.Now.AddDays(7), // token過期時間
claims: refClaims, // 該token內存儲的自定義字段信息
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用於簽發token的秘鑰算法
);
// 返回成功信息,寫出token
return Ok(new { code = 200, message = "登錄成功", accessToken = jwtSecurityTokenHandler.WriteToken(token), refreshToken = jwtSecurityTokenHandler.WriteToken(refreshToken) });
}
// 返回錯誤請求信息
return BadRequest(new { code = 400, message = "登錄失敗,用戶名或密碼為空" });
}
//此方法用來刷新令牌,邏輯是驗證refToken才能進入方法,進入后驗證accessToken除了過期時間項的其他所有項,目的是防止用戶修改權限等
[HttpPost("refresh")]
[Authorize(Roles = "refresh")]//驗證權限
public ActionResult Refresh(RefreshDto refreshDto)
{
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();//這個類是老朋友了
bool isCan =jwtSecurityTokenHandler.CanReadToken(refreshDto.AccessToken);//驗證Token格式
if (!isCan)
return BadRequest(new { code = 400, message = "傳入訪問令牌格式錯誤" });
//var jwtToken = jwtSecurityTokenHandler.ReadJwtToken(refreshDto.AccessToken);//轉換類型為token,不用這一行
var validateParameter = new TokenValidationParameters()//驗證參數
{
ValidateAudience = true,
// 驗證發布者
ValidateIssuer = true,
// 驗證過期時間
ValidateLifetime = false,
// 驗證秘鑰
ValidateIssuerSigningKey = true,
// 讀配置Issure
ValidIssuer = "cxy",
// 讀配置Audience
ValidAudience = "myClient",
// 設置生成token的秘鑰
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"))
};
//驗證傳入的過期的AccessToken
SecurityToken validatedToken = null;
try
{
jwtSecurityTokenHandler.ValidateToken(refreshDto.AccessToken, validateParameter,out validatedToken);//微軟提供的驗證方法。那個out傳出的參數,類型是是個抽象類,記得轉換
}
catch(SecurityTokenException)
{
return BadRequest(new {code=400, message= "傳入AccessToken被修改" });
}
// 獲取SecurityKey
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myJWTKeyasasasasa"));//不要學我寫這里啊,我是懶狗,寫appsettings.json這里去,寫到類的屬性里,注入一下
var refClaims = new[]
{
new Claim("role","refresh")
};
var refreshToken = new JwtSecurityToken(
issuer: "cxy", // 發布者
audience: "myClient", // 接收者
notBefore: DateTime.Now, // token簽發時間
expires: DateTime.Now.AddDays(7), // token過期時間
claims: refClaims, // 該token內存儲的自定義字段信息
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用於簽發token的秘鑰算法
);
var jwtToken = validatedToken as JwtSecurityToken;//轉換一下
var accClaims = jwtToken.Claims;
var accessToken = new JwtSecurityToken(
issuer: "cxy", // 發布者
//audience: "myClient", // 接收者
notBefore: DateTime.Now, // token簽發時間
expires: DateTime.Now.AddMinutes(30), // token過期時間
claims: accClaims, // 該token內存儲的自定義字段信息
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用於簽發token的秘鑰算法
);
// 返回成功信息,寫出token
return Ok(new {
code = 200, message = "令牌刷新成功", refreshToken =jwtSecurityTokenHandler.WriteToken(refreshToken), accessToken =new JwtSecurityTokenHandler().WriteToken(accessToken)
});
}
}
}