Springboot3+Vue3實現(xiàn)JWT登錄鑒權(quán)功能
做鑒權(quán)原因:
管理系統(tǒng)的數(shù)據(jù)是敏感的,隱私的,每個角色的權(quán)限是不同的,必須在數(shù)據(jù)的增刪改查操作時候?qū)υL問的用戶進(jìn)行權(quán)限驗證
JWT(Json Web Token)
用于在網(wǎng)絡(luò)應(yīng)用間安全的傳遞消息。它以緊湊且自包含的方式,通過JSON對象在各方之間傳遞經(jīng)過驗證的信息。JWT通常由三部分組成,用點號(.)分隔:header.payload.signature
集成JWT(在pom中引入依賴)
<!--java-JWT坐標(biāo) --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency>
生成token
/** * 生成 JWT 令牌 */ public static String createToken(String data,String sign) { return JWT.create().withAudience(data)//將userid-role保存到token里面作為載荷 .withExpiresAt(DateUtil.offsetDay(new Date(),1))//1天后token過期 .sign(Algorithm.HMAC256(sign));//以password作為token的密鑰,使用HMAC256算法加密 }
在***Service中創(chuàng)建token返回前端
String token = TokenUtil.createToken(dbUser.getId()+"-"+"管理員",dbUser.getPassword());<br data-filtered="filtered">dbUser.setToken(token);
Token格式
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxLeeuoeeQhuWRmCIsImV4cCI6MTc0MjkyMTk5Mn0.PH2OJMzhqZFuJz-aW5nWfE5wZk9fbM-tgxPql1_NNVI"
JWT攔截器對所有訪問的接口進(jìn)行驗證
通過webConfig做一層攔截器攔截所有的接口
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor()) .addPathPatterns("/**")//校驗規(guī)則所有接口 .excludePathPatterns("/login","/register");//排除登錄和注冊接口 } @Bean public JWTInterceptor jwtInterceptor(){ return new JWTInterceptor(); } }
JWT攔截器
/** * JWT攔截器 * 做攔截器的實現(xiàn) * 對Token進(jìn)行攔截并進(jìn)一步解析Token、驗證Token,看看Token是否是合法的 */ @Component public class JWTInterceptor implements HandlerInterceptor { @Resource private UserService userService; @Resource private ZuKeService zuKeService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1.從請求頭拿到Token String token=request.getHeader("token"); if (StrUtil.isEmpty(token)){ //如果沒拿到,從參數(shù)中再拿一次 token=request.getParameter("token"); } //2.認(rèn)證Token if (StrUtil.isBlank(token)){ throw new CustomException("401","您無權(quán)操作"); } Account account=null; try { //拿到Token載荷數(shù)據(jù) String audience = JWT.decode(token).getAudience().get(0); String[] split=audience.split("-"); String userId=split[0]; String role=split[1]; //柑橘Token解析出來的userId去對應(yīng)的表查詢信息 if ("管理員".equals(role)){ account=userService.selectById(userId); } else if ("租客".equals(role)) { account=zuKeService.selectById(userId); } } catch (Exception e) { throw new CustomException("401","您無權(quán)操作"); } if (account==null){ throw new CustomException("401","您無權(quán)操作"); } try { //用戶加簽 驗證簽名 JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(account.getPassword())).build(); jwtVerifier.verify(token); } catch (Exception e) { throw new CustomException("401","您無權(quán)操作"); } return true; } }
出現(xiàn)401錯誤,無權(quán)訪問數(shù)據(jù)怎么辦
在Vue的request.js的攔截器里面添加統(tǒng)一的請求頭Token
request.js的代碼
import axios from "axios"; import {ElMessage} from "element-plus"; const request = axios.create({ baseURL:'http://localhost:8080',//后端統(tǒng)一的請求地址 timeout:30000 //后臺接口時間 }) //request 攔截器 //可以自請求發(fā)送前對請求做一些處理 request.interceptors.request.use(config =>{ //統(tǒng)一的數(shù)據(jù)傳輸格式為json,統(tǒng)一的編碼utf-8 config.headers['Content-Type']='application/json;charset=utf-8'; //let user=JSON.parse(localStorage.getItem('pro1-user') || '{}'); //config.headers['token']=user.token; // ? 安全獲取 user(兼容 null 和異常情況) let user = {}; try { const userStr = localStorage.getItem('pro1-user'); user = userStr ? JSON.parse(userStr) : {}; } catch (e) { console.error('解析 pro1-user 失敗:', e); } // 僅當(dāng) token 存在時才添加到 headers if (user.token) { config.headers['token'] = user.token; } else { console.warn('Token 不存在,請求可能被后端拒絕'); // 可選:跳轉(zhuǎn)到登錄頁 // window.location.href = '/login'; } return config; },error=>{ return Promise.reject(error) }); //response攔截器 //可以在接口響應(yīng)后統(tǒng)一處理結(jié)果 request.interceptors.response.use( response =>{ let res=response.data; //兼容服務(wù)端返回的字符串?dāng)?shù)據(jù) if(typeof res === 'string'){ //如果是string,轉(zhuǎn)成json res = res ? JSON.parse(res) : res } if (res.code === '401'){ ElMessage.error(res.msg); router.push('/login') }else { return res; } }, error =>{ //后端返回數(shù)據(jù)判斷 if (error.response.status === 404){ ElMessage.error('未找到請求接口') }else if (error.response.status === 500){ ElMessage.error('系統(tǒng)異常,請查看后端控制臺報錯') }else{ console.error(error.message) } return Promise.reject(error) } ) export default request
獲取當(dāng)前登錄用戶信息
@Component public class TokenUtil { @Resource UserService userService; @Resource ZuKeService zuKeService; static UserService stasticUserService; static ZuKeService stasticZuKeService; /** * 生成 JWT 令牌 */ public static String createToken(String data,String sign) { return JWT.create().withAudience(data)//將userid-role保存到token里面作為載荷 .withExpiresAt(DateUtil.offsetDay(new Date(),1))//1天后token過期 .sign(Algorithm.HMAC256(sign));//以password作為token的密鑰,使用HMAC256算法加密 } /** * 獲取當(dāng)前登錄用戶信息 * @return */ public static Account getCurrentUser(){ Account account=null; HttpServletRequest request=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); String token=request.getHeader("token"); if (StrUtil.isEmpty(token)){ //如果沒拿到,從參數(shù)中再拿一次 token=request.getParameter("token"); } //拿到Token載荷數(shù)據(jù) String audience = JWT.decode(token).getAudience().get(0); String[] split=audience.split("-"); String userId=split[0]; String role=split[1]; if ("管理員".equals(role)){ return stasticUserService.selectById(userId); }else if ("租客".equals(role)){ return stasticZuKeService.selectById(userId); } return null; } }
在service方法里面獲取當(dāng)前登錄用戶的信息
Account currentUser=TokenUtil.getCurrentUser();
到此這篇關(guān)于Springboot3+Vue3實現(xiàn)JWT登錄鑒權(quán)的文章就介紹到這了,更多相關(guān)Springboot3+Vue3實現(xiàn)JWT登錄鑒權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在IntelliJ?IDEA中配置SSH服務(wù)器開發(fā)環(huán)境并實現(xiàn)固定地址遠(yuǎn)程連接的操作方法
本文主要介紹如何在IDEA中設(shè)置遠(yuǎn)程連接服務(wù)器開發(fā)環(huán)境,并結(jié)合Cpolar內(nèi)網(wǎng)穿透工具實現(xiàn)無公網(wǎng)遠(yuǎn)程連接,然后實現(xiàn)遠(yuǎn)程Linux環(huán)境進(jìn)行開發(fā),本例使用的是IDEA2023.2.5版本,感興趣的朋友跟隨小編一起看看吧2024-01-01Spring之兩種任務(wù)調(diào)度Scheduled和Async詳解
這篇文章主要介紹了Spring之兩種任務(wù)調(diào)度Scheduled和Async,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10手?jǐn)]一個 spring-boot-starter的全過程
這篇文章主要介紹了手?jǐn)]一個 spring-boot-starter的全過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01Java中通過三級緩存解決Spring循環(huán)依賴詳解
這篇文章主要介紹了Java中通過三級緩存解決Spring循環(huán)依賴詳解,當(dāng)出現(xiàn)兩個或多個 Bean 在初始化時相互依賴的情況時,Spring Boot 會將其中一個 Bean 提前暴露出來,以便其他 Bean 能夠在初始化時正確地引用它,這一策略能有效避免循環(huán)依賴導(dǎo)致的問題,需要的朋友可以參考下2023-09-09