1.(三)Vue实用框架-Ruoyi(token的获取)
2.jwtåtokenåºå«ï¼
3.nuxt asyncData并发请求JWT token 错乱问题
4.OAuth2.0实战!使用JWT令牌认证!
5.第4课:Spring Security Oauth2整合JWT
6.JWT令ç详解
(三)Vue实用框架-Ruoyi(token的获取)
Vue实用框架-Ruoyi(token的获取)
在Vue前端开发中,特别是基于ruoyi的前后端分离项目,理解token验证和权限渲染的实现至关重要。由于该框架基于vue-element-admin进行改造,app源码和不是源码的区别首先推荐熟悉这个框架的详细文档。 在项目代码中,频繁出现Promise,它是ES6中的异步处理工具,用于解决回调地狱的问题。在main.js中,它是项目入口,加载公共组件并初始化实例。路由管理在router目录下的index.js和permission.js中,permission.js负责权限拦截,确保只有拥有权限的好源码代下用户才能访问相关页面。 登录时,如果遇到超时重定向,会通过query参数保存登录状态。在handleLogin方法中,调用自定义的Login函数,通过store模块进行登录验证并记录token。store的使用规则明确,如缓存和接口操作分开。 登录成功后,会调用getToken()方法从cookie中获取token,随后在user.js中处理,将token用于获取用户权限并动态生成路由。整个流程清晰,通过权限拦截确保用户只能访问允许的页面。 在后端验证token时,查看/login接口的聊天源码阿login()方法,核心是调用createToken()函数生成包含用户信息的JWT令牌。jwtåtokenåºå«ï¼
JWT令ç详解
JWTæ¯JSONWebTokenç缩å,æ¯ä¸ä¸ªè½»å·§çè§è,ä¸ä¸ªå¼æ¾çè¡ä¸æ å,å®å®ä¹äºä¸ç§ç®æ´çãèªå å«çåè®®æ ¼å¼,è¿ä¸ªè§èå 许æ们使ç¨JWTå¨ç¨æ·åæå¡å¨ä¹é´ä¼ éå®å ¨å¯é çæ¶æ¯.
ä¸ä¸ªJWTå®é ä¸å°±æ¯ä¸ä¸ªå符串,å®ç±ä¸é¨åç»æ,头é¨ãè·è½½ä¸ç¾å
头é¨æè¿°å ³äºè¯¥JWTçæåºæ¬çä¿¡æ¯,ä¾å¦å ¶ç±»å以åç¾åæç¨çç®æ³ç
ä¾å¦{ "type":"JWT","alg":"HS"}
å ¶å¤´é¨ææäºç¾åç®æ³æ¯HSç®æ³
HMACç®æ³(é对称ç)
SH
RSA
è·è½½å°±æ¯åæ¾ææä¿¡æ¯çå°æ¹
å®ä¹ä¸ä¸ªpayload:{ "sub":"","name":"JohnDoe","admin":true}
ç¾è¯åç±ä¸é¨åç»æ,baseå å¯åçheaderåbaseå å¯åçpayload使ç¨,è¿æ¥ç»æçå符串
ç¶åéè¿headerä¸å£°æçå å¯æ¹å¼è¿è¡å çsecretç»åå å¯.
1ãjwtåºäºjson,é常æ¹ä¾¿è§£æ
2ãå¯ä»¥å¨ä»¤çä¸èªå®ä¹ä¸°å¯çå 容,ææ©å¼
3ãéè¿é对称å å¯ç®æ³ä»¥åæ°åç¾åææ¯,JWTé²æ¢ç¯¡æ¹,å®å ¨æ§é«
4ãèµæºæå¡ä½¿ç¨JWTå¯ä¸ä¾èµè®¤è¯æå¡å³å¯å®æææ
JWT令çè¾é¿,å åå¨ç©ºé´æ¯è¾å¤§.
ä¸ä¸ªå ¬é¥å¯¹åºä¸ä¸ªç§é¥,ç§é¥ä½ä¸ºç¾åç»JWTå å¯,é£ä¹è¿ééè¦çæä¸ä¹å¯¹åºçå ¬é¥:
è¾å ¥å¯é¥åºå£ä»¤:?keytool-list-keystorechanggou.jks
æ¾ç¤ºçä¿¡æ¯ä¸º:
å¯é¥åºç±»å:jks
å¯é¥åºæä¾æ¹:SUN
æ¨çå¯é¥åºå å«1个æ¡ç®
changgou,-7-,PrivateKeyEntry,
è¯ä¹¦æ纹(SHA1)::2E::8B::::8C:AF:::5F:4F:D6::::::
è¾å ¥å½ä»¤åå°±å¯ä»¥å¾å°å ¬é¥:
注é:classPathResource:ç§é¥ä½ç½®;
newKeyStoreKeyFactory:å建ç§é¥å·¥å,éè¦ç§é¥åºå¯ç åç§é¥ä½ç½®ä¸¤ä¸ªåæ°;
keyStoreKeyFactory.getKeyPair(alias,password.toCharArray):è·åkeyPair对象,keyPair.getPrivate()å³æ¯è·åç§é¥;
æ ¹æ®ç§é¥è·å令ç:JwtHelper.encode(JSON.toJSONString(map,newRsaSigner(rsaPrivateKey));
æ¥ï¼ç§æ®ä¸ä¸JWT1.JSONWebTokenæ¯ä»ä¹
JSONWebToken(JWT)æ¯ä¸ä¸ªå¼æ¾æ å(RFC)ï¼å®å®ä¹äºä¸ç§ç´§åçãèªå å«çæ¹å¼ï¼ç¨äºä½ä¸ºJSON对象å¨åæ¹ä¹é´å®å ¨å°ä¼ è¾ä¿¡æ¯ã该信æ¯å¯ä»¥è¢«éªè¯åä¿¡ä»»ï¼å 为å®æ¯æ°åç¾åçã
2.ä»ä¹æ¶åä½ åºè¯¥ç¨JSONWebTokens
ä¸ååºæ¯ä¸ä½¿ç¨JSONWebTokenæ¯å¾æç¨çï¼
Authorization(ææ):è¿æ¯ä½¿ç¨JWTçæ常è§åºæ¯ãä¸æ¦ç¨æ·ç»å½ï¼åç»æ¯ä¸ªè¯·æ±é½å°å å«JWTï¼å 许ç¨æ·è®¿é®è¯¥ä»¤çå 许çè·¯ç±ãæå¡åèµæºãåç¹ç»å½æ¯ç°å¨å¹¿æ³ä½¿ç¨çJWTçä¸ä¸ªç¹æ§ï¼å 为å®çå¼éå¾å°ï¼å¹¶ä¸å¯ä»¥è½»æ¾å°è·¨å使ç¨ã
InformationExchange(ä¿¡æ¯äº¤æ¢):对äºå®å ¨çå¨åæ¹ä¹é´ä¼ è¾ä¿¡æ¯èè¨ï¼JSONWebTokensæ çæ¯ä¸ç§å¾å¥½çæ¹å¼ãå 为JWTså¯ä»¥è¢«ç¾åï¼ä¾å¦ï¼ç¨å ¬é¥/ç§é¥å¯¹ï¼ä½ å¯ä»¥ç¡®å®åé人就æ¯å®ä»¬æ说çé£ä¸ªäººãå¦å¤ï¼ç±äºç¾åæ¯ä½¿ç¨å¤´åææè´è½½è®¡ç®çï¼æ¨è¿å¯ä»¥éªè¯å 容没æ被篡æ¹ã
3.JSONWebTokençç»ææ¯ä»ä¹æ ·ç
JSONWebTokenç±ä¸é¨åç»æï¼å®ä»¬ä¹é´ç¨åç¹(.)è¿æ¥ãè¿ä¸é¨ååå«æ¯ï¼
å æ¤ï¼ä¸ä¸ªå ¸åçJWTçèµ·æ¥æ¯è¿ä¸ªæ ·åçï¼
æ¥ä¸æ¥ï¼å ·ä½çä¸ä¸æ¯ä¸é¨åï¼
Header
headerå ¸åçç±ä¸¤é¨åç»æï¼tokençç±»åï¼âJWTâï¼åç®æ³å称ï¼æ¯å¦ï¼HMACSHAæè RSAççï¼ã
ä¾å¦ï¼
ç¶åï¼ç¨Base对è¿ä¸ªJSONç¼ç å°±å¾å°JWTç第ä¸é¨å
Payload
Publicclaims:å¯ä»¥éæå®ä¹ã
ä¸é¢æ¯ä¸ä¸ªä¾åï¼
对payloadè¿è¡Baseç¼ç å°±å¾å°JWTç第äºé¨å
Signature
为äºå¾å°ç¾åé¨åï¼ä½ å¿ é¡»æç¼ç è¿çheaderãç¼ç è¿çpayloadãä¸ä¸ªç§é¥ï¼ç¾åç®æ³æ¯headerä¸æå®çé£ä¸ªï¼ç¶å¯¹å®ä»¬ç¾åå³å¯ã
ä¾å¦ï¼
ç¾åæ¯ç¨äºéªè¯æ¶æ¯å¨ä¼ éè¿ç¨ä¸æ没æ被æ´æ¹ï¼å¹¶ä¸ï¼å¯¹äºä½¿ç¨ç§é¥ç¾åçtokenï¼å®è¿å¯ä»¥éªè¯JWTçåéæ¹æ¯å¦ä¸ºå®æ称çåéæ¹ã
çä¸å¼ å®ç½çå¾å°±æç½äºï¼
4.JSONWebTokensæ¯å¦ä½å·¥ä½ç
å¨è®¤è¯çæ¶åï¼å½ç¨æ·ç¨ä»ä»¬çåè¯æåç»å½ä»¥åï¼ä¸ä¸ªJSONWebTokenå°ä¼è¢«è¿åãæ¤åï¼tokenå°±æ¯ç¨æ·åè¯äºï¼ä½ å¿ é¡»é常å°å¿ä»¥é²æ¢åºç°å®å ¨é®é¢ãä¸è¬èè¨ï¼ä½ ä¿å令ççæ¶åä¸åºè¯¥è¶ è¿ä½ æéè¦å®çæ¶é´ã
æ 论ä½æ¶ç¨æ·æ³è¦è®¿é®åä¿æ¤çè·¯ç±æè èµæºçæ¶åï¼ç¨æ·ä»£çï¼é常æ¯æµè§å¨ï¼é½åºè¯¥å¸¦ä¸JWTï¼å ¸åçï¼é常æ¾å¨Authorizationheaderä¸ï¼ç¨Bearerschemaã
headeråºè¯¥çèµ·æ¥æ¯è¿æ ·çï¼
æå¡å¨ä¸çåä¿æ¤çè·¯ç±å°ä¼æ£æ¥Authorizationheaderä¸çJWTæ¯å¦ææï¼å¦æææï¼åç¨æ·å¯ä»¥è®¿é®åä¿æ¤çèµæºãå¦æJWTå å«è¶³å¤å¤çå¿ éçæ°æ®ï¼é£ä¹å°±å¯ä»¥åå°å¯¹æäºæä½çæ°æ®åºæ¥è¯¢çéè¦ï¼å°½ç®¡å¯è½å¹¶ä¸æ»æ¯å¦æ¤ã
å¦ætokenæ¯å¨ææ头ï¼Authorizationheaderï¼ä¸åéçï¼é£ä¹è·¨æºèµæºå ±äº«(CORS)å°ä¸ä¼æ为é®é¢ï¼å 为å®ä¸ä½¿ç¨cookieã
ä¸é¢è¿å¼ å¾æ¾ç¤ºäºå¦ä½è·åJWT以å使ç¨å®æ¥è®¿é®APIsæè èµæºï¼
5.åºäºTokenç身份认è¯ä¸åºäºæå¡å¨ç身份认è¯
5.1.åºäºæå¡å¨ç身份认è¯
å¨è®¨è®ºåºäºTokenç身份认è¯æ¯å¦ä½å·¥ä½ç以åå®ç好å¤ä¹åï¼æ们å æ¥çä¸ä¸ä»¥åæ们æ¯æä¹åçï¼
HTTPåè®®æ¯æ ç¶æçï¼ä¹å°±æ¯è¯´ï¼å¦ææ们已ç»è®¤è¯äºä¸ä¸ªç¨æ·ï¼é£ä¹ä»ä¸ä¸æ¬¡è¯·æ±çæ¶åï¼æå¡å¨ä¸ç¥éææ¯è°ï¼æä»¬å¿ é¡»å次认è¯
ä¼ ç»çåæ³æ¯å°å·²ç»è®¤è¯è¿çç¨æ·ä¿¡æ¯åå¨å¨æå¡å¨ä¸ï¼æ¯å¦Sessionãç¨æ·ä¸æ¬¡è¯·æ±çæ¶å带çSessionIDï¼ç¶åæå¡å¨ä»¥æ¤æ£æ¥ç¨æ·æ¯å¦è®¤è¯è¿ã
è¿ç§åºäºæå¡å¨ç身份认è¯æ¹å¼åå¨ä¸äºé®é¢ï¼
Sessions:æ¯æ¬¡ç¨æ·è®¤è¯éè¿ä»¥åï¼æå¡å¨éè¦å建ä¸æ¡è®°å½ä¿åç¨æ·ä¿¡æ¯ï¼é常æ¯å¨å åä¸ï¼éç认è¯éè¿çç¨æ·è¶æ¥è¶å¤ï¼æå¡å¨çå¨è¿éçå¼éå°±ä¼è¶æ¥è¶å¤§ã
Scalability:ç±äºSessionæ¯å¨å åä¸çï¼è¿å°±å¸¦æ¥ä¸äºæ©å±æ§çé®é¢ã
CORS:å½æ们æ³è¦æ©å±æ们çåºç¨ï¼è®©æ们çæ°æ®è¢«å¤ä¸ªç§»å¨è®¾å¤ä½¿ç¨æ¶ï¼æä»¬å¿ é¡»èèè·¨èµæºå ±äº«é®é¢ãå½ä½¿ç¨AJAXè°ç¨ä»å¦ä¸ä¸ªååä¸è·åèµæºæ¶ï¼æ们å¯è½ä¼éå°ç¦æ¢è¯·æ±çé®é¢ã
CSRF:ç¨æ·å¾å®¹æåå°CSRFæ»å»ã
5.2.JWTä¸Sessionçå·®å¼
ç¸åç¹æ¯ï¼å®ä»¬é½æ¯åå¨ç¨æ·ä¿¡æ¯ï¼ç¶èï¼Sessionæ¯å¨æå¡å¨ç«¯çï¼èJWTæ¯å¨å®¢æ·ç«¯çã
Sessionæ¹å¼åå¨ç¨æ·ä¿¡æ¯çæ大é®é¢å¨äºè¦å ç¨å¤§éæå¡å¨å åï¼å¢å æå¡å¨çå¼éã
èJWTæ¹å¼å°ç¨æ·ç¶æåæ£å°äºå®¢æ·ç«¯ä¸ï¼å¯ä»¥ææ¾åè½»æå¡ç«¯çå åååã
Sessionçç¶ææ¯åå¨å¨æå¡å¨ç«¯ï¼å®¢æ·ç«¯åªæsessionidï¼èTokençç¶ææ¯åå¨å¨å®¢æ·ç«¯ã
5.3.åºäºTokenç身份认è¯æ¯å¦ä½å·¥ä½ç
åºäºTokenç身份认è¯æ¯æ ç¶æçï¼æå¡å¨æè Sessionä¸ä¸ä¼åå¨ä»»ä½ç¨æ·ä¿¡æ¯ã
è½ç¶è¿ä¸å®ç°å¯è½ä¼ææä¸åï¼ä½å ¶ä¸»è¦æµç¨å¦ä¸ï¼
注æï¼
5.4.ç¨Tokenç好å¤
æ ç¶æåå¯æ©å±æ§ï¼Tokensåå¨å¨å®¢æ·ç«¯ãå®å ¨æ ç¶æï¼å¯æ©å±ãæ们çè´è½½åè¡¡å¨å¯ä»¥å°ç¨æ·ä¼ éå°ä»»ææå¡å¨ï¼å 为å¨ä»»ä½å°æ¹é½æ²¡æç¶ææä¼è¯ä¿¡æ¯ã
å®å ¨ï¼Tokenä¸æ¯Cookieãï¼Thetoken,notacookie.ï¼æ¯æ¬¡è¯·æ±çæ¶åTokené½ä¼è¢«åéãèä¸ï¼ç±äºæ²¡æCookie被åéï¼è¿æå©äºé²æ¢CSRFæ»å»ãå³ä½¿å¨ä½ çå®ç°ä¸å°tokenåå¨å°å®¢æ·ç«¯çCookieä¸ï¼è¿ä¸ªCookieä¹åªæ¯ä¸ç§åå¨æºå¶ï¼èé身份认è¯æºå¶ã没æåºäºä¼è¯çä¿¡æ¯å¯ä»¥æä½ï¼å 为æ们没æä¼è¯!
è¿æä¸ç¹ï¼tokenå¨ä¸æ®µæ¶é´ä»¥åä¼è¿æï¼è¿ä¸ªæ¶åç¨æ·éè¦éæ°ç»å½ãè¿æå©äºæ们ä¿æå®å ¨ãè¿æä¸ä¸ªæ¦å¿µå«tokenæ¤éï¼å®å 许æä»¬æ ¹æ®ç¸åçææ许å¯ä½¿ç¹å®çtokençè³ä¸ç»tokenæ æã
5.5.JWTä¸OAuthçåºå«
åå¨æåï¼æ为大家åå¤äºä¸äºéåäº1ï¼5年以ä¸å¼åç»éªçjavaç¨åºåé¢è¯æ¶åå°çç»å¤§é¨åé¢è¯é¢åçæ¡åæäºææ¡£åå¦ä¹ ç¬è®°æ件以åæ¶æè§é¢èµæå è´¹å享ç»å¤§å®¶ï¼å æ¬DubboãRedisãNettyãzookeeperãSpringcloudãåå¸å¼ãé«å¹¶åçæ¶æææ¯èµæï¼ï¼å¸æå¯ä»¥å¸®å©å°å¤§å®¶ã
jwtæä»ä¹ç¨JWTæ¯JSONWEBTOKENç缩åï¼å®æ¯åºäºRFCæ åå®ä¹çä¸ç§å¯ä»¥å®å ¨ä¼ è¾ççJSON对象ï¼ç±äºä½¿ç¨äºæ°åç¾åï¼æ以æ¯å¯ä¿¡ä»»åå®å ¨çã
JWTtokençæ ¼å¼ï¼header.payload.signature
headerä¸ç¨äºåæ¾ç¾åççæç®æ³
{ "alg":"HS"}CopytoclipboardErrorCopied
payloadä¸ç¨äºåæ¾ç¨æ·åãtokenççææ¶é´åè¿ææ¶é´
{ "sub":"admin","created":,"exp":}CopytoclipboardErrorCopied
signature为以headeråpayloadçæçç¾åï¼ä¸æ¦headeråpayload被篡æ¹ï¼éªè¯å°å¤±è´¥
//secret为å å¯ç®æ³çå¯é¥Stringsignature=HMACSHA(baseUrlEncode(header)+"."+baseUrlEncode(payload),secret)
JWTä¸Sessionçæ¯è¾
å¦ä»ï¼è¶æ¥è¶å¤ç项ç®å¼å§éç¨JWTä½ä¸ºè®¤è¯æææºå¶ï¼é£ä¹å®åä¹åçSession究ç«æä»ä¹åºå«å¢ï¼ä»å¤©å°±è®©æ们æ¥äºè§£ä¸ä¸ã
JWTæ¯ä»ä¹
å®ä¹
ç¹ç¹
使ç¨JWTæ¥ä¼ è¾æ°æ®ï¼å®é ä¸ä¼ è¾çæ¯ä¸ä¸ªå符串ï¼è¿ä¸ªå符串就æ¯æè°çjsonwebtokenå符串ãæ以广ä¹ä¸ï¼JWTæ¯ä¸ä¸ªæ åçå称ï¼çä¹ä¸ï¼JWTæçå°±æ¯ç¨æ¥ä¼ éçé£ä¸ªtokenå符串ãè¿ä¸ªä¸²æ两个ç¹ç¹ï¼
ç»æ
å®ç±ä¸é¨åç»æï¼headerï¼å¤´é¨ï¼ãpayloadï¼è½½è·ï¼ãsignatureï¼ç¾åï¼ï¼ä»¥.è¿è¡åå²ãï¼è¿ä¸ªå符串æ¬æ¥æ¯åªæä¸è¡çï¼æ¤å¤åæ3è¡ï¼åªæ¯ä¸ºäºåºåå ¶ç»æï¼
åSessionçåºå«
为ä»ä¹æ们è¦æJWTåSessionå对æ¯å¢ï¼å 为æ们主è¦å¨æ¯ä¸æ¬¡è¯·æ±ç认è¯æ¶ä¼ç¨JWTï¼å¨æ¤ä¹åæ们é½æ¯ç¨Sessionçãé£è¿ä¸¤è çåºå«å¨åªå¿å¢ï¼
æ¬èº«çå«ä¹
çäºåé¢çä»ç»ï¼æ们åç°JWTè¿ä¸ªåç¬¦ä¸²å ¶å®æ¬èº«å°±å å«äºå ³äºç¨æ·çä¿¡æ¯ï¼æ¯å¦ç¨æ·åãæéãè§è²çã
Sessionä¼ éçsessionIdè½ç¶æ¯ä¸ä¸ªæ´ç®åçå符串ï¼ä½å®æ¬èº«å¹¶æ²¡æä»»ä½å«ä¹ã
æ以ä¸è¬è¯´æ¥JWTçå符串è¦æ¯sessionIdé¿ï¼å¦æä½ å¨JWTä¸åå¨çä¿¡æ¯è¶é¿ï¼é£ä¹JWTæ¬èº«ä¹ä¼è¶é¿ã
èCookieçåå¨å®¹éæ¯æéå¶çï¼é常为4KBï¼ï¼æ以大家å¨ä½¿ç¨çæ¶åéè¦æ³¨æã
解ææ¹æ³
JWTçheaderåpayloadå ¶å®æ¯æjson转åè¿æ¥çï¼èsignatureå ¶å®å°±æ¯ä¸ä¸ªå å¯åçå符串ï¼å æ¤è§£æèµ·æ¥è¾ä¸ºç®åï¼ä¸éè¦å ¶ä»è¾ å©çå 容ã
sessionIdæ¯æå¡å¨åå¨çç¨æ·å¯¹è±¡çæ è¯ï¼ç论ä¸éè¦ä¸ä¸ªé¢å¤çmapæè½æ¾åºå½åç¨æ·çä¿¡æ¯ã
管çæ¹æ³
JWTç论ä¸ç¨äºæ ç¶æç请æ±ï¼å æ¤å ¶ç¨æ·ç®¡çä¹åªæ¯ä¾èµæ¬èº«èå·²ãæ们ä¸è¬æ¯å¨å®çpayloadä¸å å ¥è¿ææ¶é´ï¼å¨ä¸å¢å é¢å¤ç®¡ççæ åµä¸ï¼å®åªæèªå¨è¿æçæ¹å¼ã
Sessionå 为å®æ¬å°±æ¯åå¨å¨æå¡å¨ç«¯çï¼å æ¤ç®¡çæ¹æ¡å°±æå¾å¤ï¼èä¸å¤§å¤é½å¾æçã
跨平å°
JWTæ¬èº«å°±æ¯åºäºjsonçï¼å æ¤å®æ¯æ¯è¾å®¹æ跨平å°çï¼å¯ä»¥ä»å®ç½ä¸è½½ä¸åå¹³å°çå ï¼è§£æå³å¯ã
sessionç跨平å°å¯è½å°±ä¸é£ä¹å¥½åäºï¼éè¦èèçå°æ¹å¨äºç¨æ·ä¿¡æ¯åå¨çæ ¼å¼ï¼ProtoBufãjsonãxmlçï¼ç®¡ççè¯å¯è½å°±éè¦ä¸é¨çç»ä¸ç»å½å¹³å°ï¼è¿ä¸ªå°±ä¸å±å¼äºã
æ¶ææ§
æ ç¶æJWTä¸æ¦è¢«çæï¼å°±ä¸ä¼ååæå¡ç«¯æä»»ä½çèãä¸æ¦æå¡ç«¯ä¸çç¸å ³æ°æ®æ´æ°ï¼æ ç¶æJWTä¸åå¨çæ°æ®ç±äºå¾ä¸å°æ´æ°ï¼å°±åæäºè¿æçæ°æ®ã
sessionå°±ä¸ä¸æ ·äºï¼sessionIdæ¬èº«å°±æ²¡æ太å¤å«ä¹ï¼åªéä¿®æ¹æå¡ç«¯ä¸åå¨çæ°æ®å³å¯ã
éç¨åºæ¯
JWT
JWTçæä½³ç¨éæ¯ä¸æ¬¡æ§ææTokenï¼è¿ç§åºæ¯ä¸çTokençç¹æ§å¦ä¸ï¼
çå®åºæ¯çä¾åââæ件æ管æå¡ï¼ç±ä¸¤é¨åç»æï¼
å¦ä½æJWTç¨å¨è¿ä¸ªåºæ¯ä¸å¢ï¼
Session
Sessionæ¯è¾éç¨äºWebåºç¨çä¼è¯ç®¡çï¼å ¶ç¹ç¹ä¸è¬æ¯ï¼
æ»ç»
shiroï¼ï¼-JWTï¼Tokenççæï¼JWTï¼jsonwebtokenï¼æ¯ä¸ºäºå¨ç½ç»åºç¨ç¯å¢ä¹é´ä¼ é声æèæ§è¡çä¸ç§åºäºJSONçå¼æ¾æ åã
JWTç声æä¸è¬è¢«ç¨æ¥å¨èº«ä»½æä¾è åæå¡æä¾è é´ä¼ é被认è¯çç¨æ·èº«ä»½ä¿¡æ¯ï¼ä»¥ä¾¿ä»èµæºæå¡å¨è·åèµæºãæ¯å¦ç¨äºç»å½ã
shiroï¼9ï¼-æç¶æ身份认è¯åæ ç¶æ身份认è¯çåºå«
JWTç±ä¸é¨åç»æï¼å¤´é¨(header)ãè½½è·(payload)ãç¾å(signature)ã头é¨å®ä¹ç±»ååå å¯æ¹å¼ï¼è½½è·é¨åæ¾çä¸æ¯å¾éè¦çæ°æ®ï¼ç¾å使ç¨å®ä¹çå å¯æ¹å¼å å¯baseåçheaderåpayloadåä¸æ®µèªå·±å å¯keyãæåçtokenç±base(header).base(payload).base(signature)ç»æã
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmciOiLku4rml6XlpLTmnaEiLCJuYW1lIjoiRnJlZeeggeWGnCIsImV4cCI6MTUxNDM1NjEwMywiaWF0IjoxNTE0MzU2MDQzLCJhZ2UiOiIyOCJ9.UFvSkj-sA4aHHiYN5eoZ9Nb4w5VbPsLF7x_NY
JWT头é¨åæ¯ä¸ä¸ªæè¿°JWTå æ°æ®çJSON对象ã
å®æ´ç头é¨å°±åä¸é¢è¿æ ·çjsonã
ç¶åå°å¤´é¨è¿è¡baseå å¯ï¼ææ第ä¸é¨åï¼
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
è½½è·æ¯åæ¾ææä¿¡æ¯çå°æ¹ï¼è¿äºææé¨åå å«ä¸ä¸ªé¨åã
å ¬å ±ç声æå¯ä»¥æ·»å ä»»ä½çä¿¡æ¯ï¼ä¸è¬æ·»å ç¨æ·çç¸å ³ä¿¡æ¯æå ¶ä»ä¸å¡éè¦çå¿ è¦ä¿¡æ¯ï¼ä½ä¸å»ºè®®æ·»å ææçä¿¡æ¯ï¼å 为è¿é¨åå¨å®¢æ·ç«¯å¯è§£å¯ã
ç§æ声ææ¯æä¾è åæ¶è´¹è æå ±åå®ä¹ç声æï¼ä¸è¬ä¸å»ºè®®åæ¾ææä¿¡æ¯ï¼å 为baseæ¯å¯¹ç§°è§£å¯çï¼æå³ç该é¨åä¿¡æ¯å¯ä»¥å½ç±»ä¸ºææä¿¡æ¯ã
å®ä¹ä¸ä¸ªpayloadï¼
ç¶åå°å ¶è¿è¡baseå å¯ï¼å¾å°ç¬¬äºé¨å
eyJvcmciOiLku4rml6XlpLTmnaEiLCJuYW1lIjoiRnJlZeeggeWGnCIsImV4cCI6MTUxNDM1NjEwMywiaWF0IjoxNTE0MzU2MDQzLCJhZ2UiOiIyOCJ9
jwtç第ä¸é¨åæ¯ä¸ä¸ªç¾è¯ä¿¡æ¯ï¼è¿ä¸ªç¾è¯ä¿¡æ¯ç±ä¸é¨åç»æï¼
è¿ä¸ªé¨åéè¦baseå å¯åçheaderåbaseå å¯åçpayload使ç¨.è¿æ¥ç»æçå符串ï¼ç¶åéè¿headerä¸å£°æçå å¯æ¹å¼è¿è¡å çsecretç»åå å¯ï¼å°±ææäºjwtç第ä¸é¨åï¼
UFvSkj-sA4aHHiYN5eoZ9Nb4w5VbPsLF7x_NY
注ï¼å¯é¥secretæ¯ä¿åå¨æå¡ç«¯çï¼æå¡ç«¯ä¼æ ¹æ®è¿ä¸ªå¯é¥è¿è¡çætokenåéªè¯ï¼æ以è¦ä¿æ¤å¥½ã
解æç»æ
éæ¾æ»å»æ¯æ»å»è è·å客æ·ç«¯åéç»æå¡å¨ç«¯çå ï¼ä¸åä¿®æ¹ï¼åå°ä¸å¨çåéç»æå¡å¨ç¨æ¥å®ç°æäºåè½ãæ¯å¦è¯´å®¢æ·ç«¯åéç»æå¡å¨ç«¯ä¸ä¸ªå çåè½æ¯æ¥è¯¢æ个信æ¯ï¼æ»å»è æ¦æªå°è¿ä¸ªå ï¼ç¶åæ³è¦æ¥è¯¢è¿ä¸ªä¿¡æ¯çæ¶åï¼æè¿ä¸ªå åéç»æå¡å¨ï¼æå¡å¨å°±ä¼åç¸åºçæä½ï¼è¿åæ¥è¯¢çä¿¡æ¯ã
é´æå¿ é¡»äºè§£ç5个å å¼ï¼cookieãsessionãtokenãjwtãåç¹ç»å½æ¬æä½ å°çå°ï¼
**ãå端åå¨ã**è¿å°±æ¶åå°ä¸åãä¸åãä¸å¸¦ï¼å好åï¼ç»éæ¥å£ç´æ¥è¿åç»å端ï¼åå¨å°±éè¦å端æ³åæ³äºã
å端çåå¨æ¹å¼æå¾å¤ã
æï¼cookieãcookieä¹æ¯å端åå¨çä¸ç§ï¼ä½ç¸æ¯äºlocalStorageçå ¶ä»æ¹å¼ï¼åå©HTTP头ãæµè§å¨è½åï¼cookieå¯ä»¥åå°å端æ æç¥ãä¸è¬è¿ç¨æ¯è¿æ ·çï¼
ãé ç½®ï¼Domain/Pathã
cookieæ¯è¦éå¶::ã空é´èå´ã::çï¼éè¿Domainï¼åï¼/Pathï¼è·¯å¾ï¼ä¸¤çº§ã
ãé ç½®ï¼Expires/Max-Ageã
cookieè¿å¯ä»¥éå¶::ãæ¶é´èå´ã::ï¼éè¿ExpiresãMax-Ageä¸çä¸ç§ã
ãé ç½®ï¼Secure/HttpOnlyã
cookieå¯ä»¥éå¶::ã使ç¨æ¹å¼ã::ã
**ãHTTP头对cookieç读åã**åè¿å¤´æ¥ï¼HTTPæ¯å¦ä½åå ¥åä¼ écookieåå ¶é ç½®çå¢ï¼HTTPè¿åçä¸ä¸ªSet-Cookie头ç¨äºåæµè§å¨åå ¥ãä¸æ¡ï¼ä¸åªè½æ¯ä¸æ¡ï¼ãcookieï¼æ ¼å¼ä¸ºcookieé®å¼+é ç½®é®å¼ãä¾å¦ï¼
é£ææ³ä¸æ¬¡å¤setå 个cookieæä¹åï¼å¤ç»å 个Set-Cookie头ï¼ä¸æ¬¡HTTP请æ±ä¸å 许éå¤ï¼
HTTP请æ±çCookie头ç¨äºæµè§å¨æ符åå½åã空é´ãæ¶é´ã使ç¨æ¹å¼ãé ç½®çææcookieä¸å¹¶åç»æå¡ç«¯ãå 为ç±æµè§å¨åäºçéå¤æï¼å°±ä¸éè¦å½è¿é ç½®å 容äºï¼åªè¦åéé®å¼å°±å¯ä»¥ã
**ãå端对cookieç读åã**å端å¯ä»¥èªå·±å建cookieï¼å¦ææå¡ç«¯å建çcookie没å HttpOnlyï¼é£æåä½ ä¹å¯ä»¥ä¿®æ¹ä»ç»çcookieãè°ç¨document.cookieå¯ä»¥å建ãä¿®æ¹cookieï¼åHTTPä¸æ ·ï¼ä¸æ¬¡document.cookieè½ä¸åªè½æä½ä¸ä¸ªcookieã
è°ç¨document.cookieä¹å¯ä»¥è¯»å°cookieï¼ä¹åHTTPä¸æ ·ï¼è½è¯»å°ææçéHttpOnlycookieã
ç°å¨åæ³ä¸ï¼ä½ å·å¡çæ¶ååçäºä»ä¹ï¼
è¿ç§æä½ï¼å¨åå端é´æç³»ç»ä¸ï¼å«sessionãå ¸åçsessionç»é/éªè¯æµç¨ï¼
**ãSessionçåå¨æ¹å¼ã**æ¾ç¶ï¼æå¡ç«¯åªæ¯ç»cookieä¸ä¸ªsessionIdï¼èsessionçå ·ä½å 容ï¼å¯è½å å«ç¨æ·ä¿¡æ¯ãsessionç¶æçï¼ï¼è¦èªå·±åä¸ä¸ãåå¨çæ¹å¼æå ç§ï¼
ãSessionçè¿æåéæ¯ã**å¾ç®åï¼åªè¦æåå¨çsessionæ°æ®éæ¯å°±å¯ä»¥ã****ãSessionçåå¸å¼é®é¢ã**é常æå¡ç«¯æ¯é群ï¼èç¨æ·è¯·æ±è¿æ¥ä¼èµ°ä¸æ¬¡è´è½½åè¡¡ï¼ä¸ä¸å®æå°åªå°æºå¨ä¸ãé£ä¸æ¦ç¨æ·åç»æ¥å£è¯·æ±å°çæºå¨åä»ç»å½è¯·æ±çæºå¨ä¸ä¸è´ï¼æè ç»å½è¯·æ±çæºå¨å®æºäºï¼sessionä¸å°±å¤±æäºåï¼è¿ä¸ªé®é¢ç°å¨æå ç§è§£å³æ¹å¼ã
ä½é常è¿æ¯éç¨ç¬¬ä¸ç§æ¹å¼ï¼å 为第äºç§ç¸å½äºéå²äºè´è½½åè¡¡ï¼ä¸ä»æ²¡æ解å³ãç¨æ·è¯·æ±çæºå¨å®æºãçé®é¢ã**ãnode.jsä¸çsessionå¤çã**åé¢çå¾å¾æ¸ æ¥äºï¼æå¡ç«¯è¦å®ç°å¯¹cookieåsessionçååï¼å®ç°èµ·æ¥è¦åçäºè¿æ¯å¾å¤çãå¨npmä¸ï¼å·²ç»æå°è£ 好çä¸é´ä»¶ï¼æ¯å¦express-session-npmï¼ç¨æ³å°±ä¸è´´äºãè¿æ¯å®ç§çcookieï¼
express-session-npm主è¦å®ç°äºï¼
sessionçç»´æ¤ç»æå¡ç«¯é æå¾å¤§å°æ°ï¼æä»¬å¿ é¡»æ¾å°æ¹åæ¾å®ï¼åè¦èèåå¸å¼çé®é¢ï¼çè³è¦åç¬ä¸ºäºå®å¯ç¨ä¸å¥Redisé群ãæ没ææ´å¥½çåæ³ï¼
åè¿å¤´æ¥æ³æ³ï¼ä¸ä¸ªç»å½åºæ¯ï¼ä¹ä¸å¿ å¾sessionå太å¤ä¸è¥¿ï¼é£ä¸ºä»ä¹ä¸ç´æ¥æå å°cookieä¸å¢ï¼è¿æ ·æå¡ç«¯ä¸ç¨åäºï¼æ¯æ¬¡åªè¦æ ¸éªcookie带çãè¯ä»¶ãæææ§å°±å¯ä»¥äºï¼ä¹å¯ä»¥æºå¸¦ä¸äºè½»éçä¿¡æ¯ãè¿ç§æ¹å¼é常被å«åtokenã
tokençæµç¨æ¯è¿æ ·çï¼
**ã客æ·ç«¯tokençåå¨æ¹å¼ãå¨åé¢cookie说è¿ï¼cookie并ä¸æ¯å®¢æ·ç«¯åå¨åè¯çå¯ä¸æ¹å¼ãtokenå 为å®çãæ ç¶ææ§ãï¼æææã使ç¨éå¶é½å å¨tokenå 容éï¼å¯¹cookieç管çè½åä¾èµè¾å°ï¼å®¢æ·ç«¯åèµ·æ¥å°±æ¾å¾æ´èªç±ãä½webåºç¨ç主æµæ¹å¼ä»æ¯æ¾å¨cookieéï¼æ¯ç«å°æå¿ããtokençè¿æã**é£æ们å¦ä½æ§å¶tokençæææå¢ï¼å¾ç®åï¼æãè¿ææ¶é´ãåæ°æ®ä¸èµ·å¡è¿å»ï¼éªè¯æ¶å¤æ就好ã
ç¼ç çæ¹å¼ä¸°ä¿ç±äººã**ãbaseã**æ¯å¦node端çcookie-session-npmåº
é»è®¤é ç½®ä¸ï¼å½æç»ä»ä¸ä¸ªuseridï¼ä»ä¼åæè¿æ ·ï¼
è¿éçeyJ1c2VyaWQiOiJhIn0=ï¼å°±æ¯{ "userid":"abbâ}çbaseèå·²ããé²ç¯¡æ¹ã
æ¯çãæ以çæ åµï¼å¦ætokenæ¶åå°æææéï¼å°±è¦æ³åæ³é¿å token被篡æ¹ã解å³æ¹æ¡å°±æ¯ç»tokenå ç¾åï¼æ¥è¯å«tokenæ¯å¦è¢«ç¯¡æ¹è¿ãä¾å¦å¨cookie-session-npmåºä¸ï¼å¢å 两项é ç½®ï¼
è¿æ ·ä¼å¤ç§ä¸ä¸ª.sigcookieï¼éé¢çå¼å°±æ¯{ "userid":"abbâ}åiAmSecretéè¿å å¯ç®æ³è®¡ç®åºæ¥çï¼å¸¸è§çæ¯å¦HMACSHAç±»(System.Security.Cryptography)|MicrosoftDocsã
好äºï¼ç°å¨cddè½ç¶è½ä¼ªé åºeyJ1c2VyaWQiOiJhIn0=ï¼ä½ä¼ªé ä¸åºsigçå 容ï¼å 为ä»ä¸ç¥ésecretã**ãJWTã**ä½ä¸é¢çåæ³é¢å¤å¢å äºcookieæ°éï¼æ°æ®æ¬èº«ä¹æ²¡æè§èçæ ¼å¼ï¼æ以JSONWebTokenIntroduction-jwt.io横空åºä¸
nuxt asyncData并发请求JWT token 错乱问题
遇到的问题是JWT token认证的前后端分离项目中,用户A和用户B同时请求同一页面时,各自接收到的数据错乱。具体表现为用户A获取到用户B的数据,而用户B获取到用户A的数据。页面的asyncData方法包含两个并发请求,发现即使只有一个"/api/1"请求,使用了$axios在服务端发起请求,也会导致token错乱问题。
在plugins/axios.js文件中,获取token的方式无论是store.state.token还是req.headers.cookie,问题依旧存在。在服务端打印的日志显示在进入$axios设置时,$axios.setHeader('Authorization',`JWT ${ token}`);这行代码确实在服务端执行。通过这个日志,古玛家源码我们得知问题出现在服务端,且与$axios的注入有关。
暂时还未找到准确原因,期待有经验的开发者能提供解决方案。可能原因包括注入方式、服务端执行环境、或$axios的使用方式不当。等待专业人士解析。
为解决此问题,推荐不使用注入Vue对象内的$axios,而是改用axios。这样可以将全局拦截器的设置放在actions里的nuxtServerInit方法下。确保导入axios模块:`import axios from 'axios';`。通过这种方法,可以有效避免在服务端注入$axios带来的潜在问题,从而解决JWT token错乱问题。高智稳源码
最后,需要在请求页面的asyncData方法中,合理使用axios发起请求,确保token正确注入。这样,前后端分离的项目中,用户的请求将能够准确获取到对应的数据,避免数据错乱的问题。
OAuth2.0实战!使用JWT令牌认证!
本文介绍OAuth2.0集成JWT颁发令牌的实践,这是企业中应用广泛的令牌形式。
OAuth2.0中的令牌分为透明和不透明两种类型。不透明令牌是仅包含随机字符串,如UUID,资源服务需调用认证授权服务的接口进行校验,导致高并发下性能低下。相比之下,透明令牌如JWT,直接存储用户信息,资源服务可自行解析,无需额外调用校验接口。
JWT由三部分构成:头部、载荷和签名。头部定义令牌基本信息,如类型和加密算法。载荷包含用户信息等元数据。签名部分使用头部定义的算法结合密钥生成,确保数据完整性和安全性。
在OAuth2.0认证授权服务搭建中,JWT作为透明令牌,简化了令牌验证过程。首先,创建oauth2-auth-server-jwt模块,继承并修改上文关于OAuth2.0的代码。配置JWT相关的类,包括令牌增强类、令牌存储策略和签名密钥。使用JwtAccessTokenConverter进行JWT和OAuth身份转换,配置TokenStore为JWT生成方式,同时注意在实际应用中应使用非对称加密以增强安全性。
接下来,为授权服务配置令牌管理,使用DefaultTokenServices实现,设置令牌过期时间,并通过JWT方式生成访问令牌。在AuthorizationServerEndpointsConfigurer中添加令牌服务。至此,认证中心JWT令牌生成方式配置完成。
资源服务方面,构建oauth2-auth-resource-jwt模块,复用授权服务的配置,注意JWT加密密钥需与认证中心一致。配置令牌服务,生成ResourceServerTokenServices对象,结合JWT增强。将资源ID和令牌服务配置到ResourceServerSecurityConfigurer中,以实现资源访问。
测试阶段,通过获取令牌并调用资源服务接口验证逻辑是否正确。使用POSTMAN请求获取访问令牌,并使用获取的访问令牌调用资源服务接口进行测试。JWT令牌验证成功。
源码追踪环节,解析获取令牌和校验令牌的过程。获取令牌主要在TokenEndpoint处理,通过ClientDetailsService加载客户端信息,使用DefaultTokenServices生成并返回OAuth2AccessToken。校验令牌则在OAuth2AuthenticationProcessingFilter中完成,调用OAuth2AuthenticationManager的authenticate()方法实现令牌验证。
第4课:Spring Security Oauth2整合JWT
本文详细介绍了Spring Security Oauth2整合JWT的过程,包括代码地址、项目介绍与配置、开始测试等步骤。
项目配置包括引入JWT、配置TokenStore、JwtTokenEnhancer补充额外信息、WebSecurityConfig、ResourceServiceConfig、AuthorizationServerConfig、自定义登录页面、自定义授权页面、UserController与MyUserDetailsService。
测试流程包括获取授权地址、跳转至登录页面输入用户名与密码、跳转至授权页面并授权、通过POST请求获取令牌token,以及根据token获取user信息。最后部分鼓励读者收藏文章,以便日后参考,欢迎在评论区分享学习体会。
JWT令ç详解
JWTæ¯JSON Web Tokenç缩å,æ¯ä¸ä¸ªè½»å·§çè§è,ä¸ä¸ªå¼æ¾çè¡ä¸æ å,å®å®ä¹äºä¸ç§ç®æ´çãèªå å«çåè®®æ ¼å¼,è¿ä¸ªè§èå 许æ们使ç¨JWTå¨ç¨æ·åæå¡å¨ä¹é´ä¼ éå®å ¨å¯é çæ¶æ¯.
ä¸ä¸ªJWTå®é ä¸å°±æ¯ä¸ä¸ªå符串,å®ç±ä¸é¨åç»æ,头é¨ãè·è½½ä¸ç¾å
头é¨æè¿°å ³äºè¯¥JWTçæåºæ¬çä¿¡æ¯,ä¾å¦å ¶ç±»å以åç¾åæç¨çç®æ³ç
ä¾å¦{ "type":"JWT","alg":"HS"}
å ¶å¤´é¨ææäºç¾åç®æ³æ¯HSç®æ³
HMACç®æ³(é对称ç)
SH
RSA
è·è½½å°±æ¯åæ¾ææä¿¡æ¯çå°æ¹
å®ä¹ä¸ä¸ªpayload:{ "sub":"","name":"John Doe","admin":true}
ç¾è¯åç±ä¸é¨åç»æ,baseå å¯åçheaderåbaseå å¯åçpayload使ç¨,è¿æ¥ç»æçå符串
ç¶åéè¿headerä¸å£°æçå å¯æ¹å¼è¿è¡å çsecretç»åå å¯.
1ãjwtåºäºjson,é常æ¹ä¾¿è§£æ
2ãå¯ä»¥å¨ä»¤çä¸èªå®ä¹ä¸°å¯çå 容,ææ©å¼
3ãéè¿é对称å å¯ç®æ³ä»¥åæ°åç¾åææ¯,JWTé²æ¢ç¯¡æ¹,å®å ¨æ§é«
4ãèµæºæå¡ä½¿ç¨JWTå¯ä¸ä¾èµè®¤è¯æå¡å³å¯å®æææ
JWT令çè¾é¿,å åå¨ç©ºé´æ¯è¾å¤§.
ä¸ä¸ªå ¬é¥å¯¹åºä¸ä¸ªç§é¥,ç§é¥ä½ä¸ºç¾åç»JWTå å¯,é£ä¹è¿ééè¦çæä¸ä¹å¯¹åºçå ¬é¥:
è¾å ¥å¯é¥åºå£ä»¤: keytool -list -keystore changgou.jks
æ¾ç¤ºçä¿¡æ¯ä¸º:
å¯é¥åºç±»å: jks
å¯é¥åºæä¾æ¹: SUN
æ¨çå¯é¥åºå å« 1 个æ¡ç®
changgou, -7-, PrivateKeyEntry,
è¯ä¹¦æ纹 (SHA1): :2E::8B::::8C:AF:::5F:4F:D6::::::
è¾å ¥å½ä»¤åå°±å¯ä»¥å¾å°å ¬é¥:
注é:classPathResource:ç§é¥ä½ç½®;
new KeyStoreKeyFactory:å建ç§é¥å·¥å,éè¦ç§é¥åºå¯ç åç§é¥ä½ç½®ä¸¤ä¸ªåæ°;
keyStoreKeyFactory.getKeyPair(alias,password.toCharArray):è·åkeyPair对象,keyPair.getPrivate()å³æ¯è·åç§é¥;
æ ¹æ®ç§é¥è·å令ç:JwtHelper.encode(JSON.toJSONString(map,new RsaSigner(rsaPrivateKey));