天天看點

C# .Net Furion Jwt登入與自動重新整理token前端後端

前端

axios設定

// 建立一個axios對象
let instance = axios.create({
    baseURL: 'http://localhost:5001/api',
    timeout: 15000,
});
// key 的名稱
let _tokenKey = 'access-token';
let _refreshTokenKey = 'x-access-token';

// 請求攔截
instance.interceptors.request.use(
    function (config) {
        // 取出存儲的token
        let token = localStorage.getItem(_tokenKey);
        let refreshToken = localStorage.getItem(_refreshTokenKey);
        // 判斷是否進行了登入
        if (token != null && refreshToken != null) {
            config.headers['Authorization'] = 'Bearer ' + token;
            config.headers['X-Authorization'] = 'Bearer ' + refreshToken;
        }
        return config;
    },
    function (error) {
        return Promise.reject(error);
    }
);
// 響應攔截
instance.interceptors.response.use(
    function (response) {
        // 伺服器傳回的headers
        let headers = response.headers;
        let token = headers[_tokenKey];
        let refreshToken = headers[_refreshTokenKey];
        // 判斷是否有傳回的token(登入和自動重新整理都在headers中設定了token)
        if (token != null && refreshToken != null) {
            console.log('存儲token');
            //存到localStorage,發送請求時取出
            localStorage.setItem(_tokenKey, token);
            localStorage.setItem(_refreshTokenKey, refreshToken);
        }
        return response;
    },
    function (error) {
        // 對響應錯誤做點什麼
        console.error(error);
        alert('發生了錯誤');
        return Promise.reject(error);
    }
);
           

測試

let login = () => {
    instance.post('/user/login', {}).then((r) => {
        console.log('login 傳回:', r);
    });
};
let test = () => {
    instance.post('/user/test-jwt',{}).then((r) => {
    	//未登入 傳回 401
    	//登入後傳回   1----xxxue
        console.log('test 傳回:', r);
    });
};
           

後端

controller

using System.Collections.Generic;
using Furion;
using Furion.DataEncryption;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

namespace Demo.Application.UserController
{
    public class UserAppServices : IDynamicApiController
    {
        // httpContext 通路器
        private readonly IHttpContextAccessor _httpContextAccessor;

        public UserAppServices(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// Jwt登入
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous] // 允許匿名通路
        public bool Login()
        {
        	// 真實項目中, 需要從資料庫查詢使用者資訊
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            {
                { "UserId", 1 },
                { "UserName", "xxxue" }
            }, 1); // 過期時間 1分鐘,用于測試

            // 下面設定 headers["access-token"] 即可登入. 這裡無需重複設定
            //_httpContextAccessor.HttpContext.SigninToSwagger(accessToken);

            // 預設30天,可指定第二個參數設定有效期
            var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken);
            if (_httpContextAccessor.HttpContext != null)
            {
                _httpContextAccessor.HttpContext.Response.Headers["access-token"] = accessToken;
                _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
                // 指定公開的key,這樣 axios才能取到值
                _httpContextAccessor.HttpContext.Response.Headers["Access-Control-Expose-Headers"] =
                    "access-token, x-access-token";
            }

            return !string.IsNullOrEmpty(accessToken);
        }

        public string TestJwt()
        {
            // 取出jwt中存儲的值
            var id = App.User.FindFirst("UserId");
            var userName = App.User.FindFirst("UserName");
            return id + " --- " + userName;
        }
    }
}
           

JwtHandler

using System;
using Furion.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Furion.DataEncryption;

namespace Demo.Web.Core
{
    public class JwtHandler : AppAuthorizeHandler
    {
        public override async Task HandleAsync(AuthorizationHandlerContext context)
        {
            Console.WriteLine("進入jwt驗證");
            
            var currentHttpContext = context.GetCurrentHttpContext();
            // 檢查并自動重新整理 token, (第三個參數,新token有效期設定為1分鐘,便于測試)
            if (JWTEncryption.AutoRefreshToken(context, currentHttpContext, 1))
            {
                await AuthorizeHandleAsync(context);
            }
            else
            {
                context.Fail(); // 授權失敗
            }
        }

        public override Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
        {
            // 這裡寫您的授權判斷邏輯,授權通過傳回 true,否則傳回 false
            return Task.FromResult(true);
        }
    }
}


           

startup

using Furion;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Serilog;

namespace Demo.Web.Core
{
    public class Startup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        	// 注冊jwt處理方法,開啟全局驗證,
        	//除了标注 [AllowAnonymous] 特性,其他的方法都需要登入才可以通路
            services.AddJwt<JwtHandler>(enableGlobalAuthorize:true);
            
			//.. 省略
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
			//.. 省略
			// 開啟認證
			app.UseAuthentication();
			app.UseAuthorization();
			//.. 省略
        }
    }
}

           

繼續閱讀