前端
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();
//.. 省略
}
}
}