1. 程式人生 > 其它 >ASP.NET Core生成,校驗jwt的(accessToken)訪問令牌和(refreshToken)重新整理令牌示例講解

ASP.NET Core生成,校驗jwt的(accessToken)訪問令牌和(refreshToken)重新整理令牌示例講解

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)
            });
        }
    }
}