最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot+vue+Axios實(shí)現(xiàn)Token令牌的詳細(xì)過程

 更新時(shí)間:2023年10月14日 09:30:45   作者:涼冰24  
Token是在服務(wù)端產(chǎn)生的,前端可以使用用戶名/密碼向服務(wù)端請(qǐng)求認(rèn)證(登錄),服務(wù)端認(rèn)證成功,服務(wù)端會(huì)返回?Token?給前端,Token可以使用自己的算法自定義,本文給大家介紹SpringBoot+vue+Axios實(shí)現(xiàn)Token令牌,感興趣的朋友一起看看吧

認(rèn)識(shí)Token

對(duì)Token有了解可以跳過。

使用Token存儲(chǔ)用戶信息,認(rèn)證用戶。 Token是一個(gè)訪問系統(tǒng)的令牌(字符串)。Token 是在服務(wù)端產(chǎn)生的。前端可以使用用戶名/密碼向服務(wù)端請(qǐng)求認(rèn)證(登錄),服務(wù)端認(rèn)證成功,服務(wù)端會(huì)返回 Token 給前端。前端可以在每次請(qǐng)求的時(shí)候帶上 Token 證明自己的身份。服務(wù)器端在處理請(qǐng)求之前,先驗(yàn)證Token,驗(yàn)證通過,可以訪問系統(tǒng),執(zhí)行業(yè)務(wù)請(qǐng)求處理。

Token可以使用自己的算法自定義,比如給每個(gè)用戶分配一個(gè)UUID ,UUID值就看做是一個(gè)Token 。

Token統(tǒng)一的規(guī)范是JWT( json web token ) 。用json表示token。JWT定義了一種緊湊而獨(dú)立的方法,用于在各方之間安全地將信息作為JSON對(duì)象傳輸。

常使用的Token庫是 jjwt

JWT組成

JWT這是一個(gè)很長的字符串,中間用點(diǎn)(.)分隔成三個(gè)部分。JWT 內(nèi)部是沒有換行的,一行數(shù)據(jù)。

JWT 的三個(gè)部分依次如下。

Header(頭部)

Payload(負(fù)載)

Signature(簽名)

形如:

eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTE5NzgzNDQsImlhdCI6MTY5MTk3Nzc0NCwianRpIjoiNDEyNjRhNTctYTY0ZC00Y2E5LTljMzMtY2I1MGJmNDc5YjEzIiwicm9sZSI6Iue7j-eQhiIsIm5hbWUiOiLmnY7lm5siLCJ1c2VySWQiOjEwMDF9.t4IrCIs8Y1zLwehouUugeAc-8PBlndpXz5xhibtQIgo

Header

Header: 是一個(gè)json對(duì)象,存儲(chǔ)元數(shù)據(jù)

{
	"alg": "HS256", // alg:是簽名的算法名稱(algorithm),默認(rèn)是 HMAC SHA256(寫成 HS256);
	"typ": "JWT"	//typ屬性表示這個(gè)令牌(token)的類型(type),JWT 令牌統(tǒng)一寫為JWT。
}

元數(shù)據(jù)的json對(duì)象使用base64URL編碼.

Payload

Payload :負(fù)載,是一個(gè)json對(duì)象。是存放傳遞的數(shù)據(jù) ,數(shù)據(jù)分為Public的和Private的。

Public是JWT中規(guī)定的一些字段,可以自己選擇使用。

  • iss (issuer):簽發(fā)人
  • exp (expiration time):過期時(shí)間
  • sub (subject):該JWT所面向的用戶
  • aud (audience):受眾,接收該JWT的一方
  • nbf (Not Before):生效時(shí)間
  • iat (Issued At):簽發(fā)時(shí)間
  • jti (JWT ID):編號(hào)

Private是自己定義的字段

{
 "role": "經(jīng)理",
 "name": "張凡",
 "id": 2345
}

Playload默認(rèn)是沒有加密的, 以上數(shù)據(jù)都明文傳輸?shù)?,所?strong>不要放敏感數(shù)據(jù).此部分?jǐn)?shù)據(jù)也是json對(duì)象使用base64URL編碼,是一個(gè)字符串

Signature

Signature:簽名。簽名是對(duì)Header和Payload兩部分的簽名,目的是防止數(shù)據(jù)被篡改

HMACSHA256(
 base64UrlEncode(header) + "." +
 base64UrlEncode(payload),
 secret)

簽名算法:先指定一個(gè) secret秘鑰, 把base64URL的header , base64URL的payload 和 secret秘鑰 使用 HMAC SHA256 生成簽名字符串

JWT簡單使用

  • 首先用戶使用類似像用戶名,密碼登錄服務(wù)器,校驗(yàn)用戶身份,服務(wù)器返回jwt token

  • 客戶端獲取 jwt token , 使用cookie或者localStorage存儲(chǔ)jwt token,但這樣不能跨域, 常用的方式:

    • 放在請(qǐng)求header 的 Authorization中 Authorization: Bearer

    • 也可以放在 get 或者 post請(qǐng)求的參數(shù)中

  • 客戶端訪問其他api接口, 傳遞token給服務(wù)器, 服務(wù)器認(rèn)證token后,返回給請(qǐng)求的數(shù)據(jù)

創(chuàng)建JWT

@Test
public void testCreateJwt(){
    String key = "7d8e742c14674758b9162892eec9c59c";// 32位、全局唯一

    // 創(chuàng)建secereKey
    SecretKey secretKey = Keys.hmacShaKeyFor(key.getBytes(StandardCharsets.UTF_8));

    // 存儲(chǔ)用戶數(shù)據(jù)
    Map<String,Object> map = new HashMap();
    map.put("userId",1001);
    map.put("name","李四");
    map.put("role","經(jīng)理");
	// 獲取簽發(fā)時(shí)間
    Date curDate = new Date();
    // 創(chuàng)建jwt
    String jwt = Jwts.builder().signWith(secretKey, SignatureAlgorithm.HS256)		// Header
                                .setExpiration(DateUtils.addMinutes(curDate, 10))	// 設(shè)置10分鐘后過期
                                .setIssuedAt(curDate)								// 設(shè)置簽發(fā)時(shí)間
                                .setId(UUID.randomUUID().toString())				// Token唯一編號(hào)
                                .addClaims(map).compact();							// 添加有關(guān)用戶或其他實(shí)體的聲明信息
    System.out.println("jwt = " + jwt);
    // eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTE5NzgzNDQsImlhdCI6MTY5MTk3Nzc0NCwianRpIjoiNDEyNjRhNTctYTY0ZC00Y2E5LTljMzMtY2I1MGJmNDc5YjEzIiwicm9sZSI6Iue7j-eQhiIsIm5hbWUiOiLmnY7lm5siLCJ1c2VySWQiOjEwMDF9.t4IrCIs8Y1zLwehouUugeAc-8PBlndpXz5xhibtQIgo
}

解析JWT

@Test
public void testReadJwt(){
    String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTE5Nzk4MTMsImlhdCI6MTY5MTk3OTIxMywianRpIjoiYzAyYzRiMzMtODAzZS00MDk1LWI0NTctZjVmY2NkYTMyOTU2Iiwicm9sZSI6Iue7j-eQhiIsIm5hbWUiOiLmnY7lm5siLCJ1c2VySWQiOjEwMDF9.vUsmvOF-rv6XVCzuNgJZCGBohzDeROUFUf-c3iRv6NA";
    String key = "7d8e742c14674758b9162892eec9c59c";// 加密用的32位key

    // 創(chuàng)建secretKey
    SecretKey secretKey = Keys.hmacShaKeyFor(key.getBytes(StandardCharsets.UTF_8));

    // 解析Jwt 沒有異常 解析成功
    Jws<Claims> claims = Jwts.parserBuilder() 				// 1.獲取Buider對(duì)象
        .setSigningKey(secretKey) 	// 2.設(shè)置key
        .build()					// 3.獲取Parser
        .parseClaimsJws(jwt);		// 4.解析數(shù)據(jù)
    // 讀數(shù)據(jù)
    Claims body = claims.getBody();

    Integer userId = body.get("userId",Integer.class);
    System.out.println("userId = " + userId);

    Object uId = body.get("userId");
    System.out.println("uId = " + uId);

    Object name = body.get("name");
    if(name != null){
        System.out.println("name = " + name);
    }

    String jwtId = body.getId();
    System.out.println("jwtId = " + jwtId);

    Date expiration = body.getExpiration();
    System.out.println("expiration = " + expiration);

}

常見異常

ClaimJwtException 獲取Claim異常

ExpiredJwtException token過期異常

IncorrectClaimException token無效

MalformedJwtException 密鑰驗(yàn)證不一致

MissingClaimException JWT無效

RequiredTypeException 必要類型異常

SignatureException 簽名異常

UnsupportedJwtException 不支持JWT異常

后端

Maven依賴

<!--jwt-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

封裝JWT工具

public class JwtUtile {
	// 全局唯一、亂序的32位字符串。存儲(chǔ)在配置文件中
    private String selfKey;

    public JwtUtile(String selfKey) {
        this.selfKey = selfKey;
    }

    // 創(chuàng)建Token
    public String creatJwt(Map<String,Object> data,Integer minute) throws Exception{
        Date cruDate = new Date();
        SecretKey secretKey = Keys.hmacShaKeyFor(selfKey.getBytes(StandardCharsets.UTF_8));
        String jwt = Jwts.builder().signWith(secretKey, SignatureAlgorithm.HS256)
                .setExpiration(DateUtils.addMinutes(cruDate, minute))
                .setIssuedAt(cruDate)
                .setId(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase())
                .addClaims(data)
                .compact();
        return jwt;
    }
    // 讀取Jwt
    public Claims readJWT(String jwt) throws Exception{
        SecretKey secretKey = Keys.hmacShaKeyFor(selfKey.getBytes(StandardCharsets.UTF_8));
        Claims body = Jwts.parserBuilder().setSigningKey(secretKey)
                .build().parseClaimsJws(jwt).getBody();
        return body;
    }

}

獲取并響應(yīng)Token

@PostMapping("/login")
public RespResult userLogin(@RequestParam String phone,
                            @RequestParam String pword,
                            @RequestParam String scode) throws Exception{
    RespResult result = RespResult.fail();
    if (CommonUtil.checkPhone(phone) && (pword != null || pword.length() == 32)) {
        // 檢查驗(yàn)證碼是否正確
        if (loginSmsService.checkSmsCode(phone, scode)) {
            // 查找是否存賬號(hào)密碼匹配用戶
            User user = userService.userLogin(phone, pword);
            if (user != null) {
                // 登錄成功 , 生成Token
                Map<String ,Object> data = new HashMap<>();
                data.put("uid",user.getId());// 設(shè)置荷載位uid
                // 設(shè)置120分鐘過期,并獲取Token
                String jwtToken = jwtUtile.creatJwt(data, 120);

                result = RespResult.ok();
                // 響應(yīng)Token
                result.setAccessToken(jwtToken);

                Map<String,Object> userInfo = new HashMap<>();
                userInfo.put("uid",user.getId());
                userInfo.put("phone",user.getPhone());
                userInfo.put("name",user.getName());
                result.setData(userInfo);
            }else {
                result.setRCode(RCode.PHONE_LOGIN_PASSWORD_INVALID);
            }
        } else {
            result.setRCode(RCode.SMS_CODE_INVALID);
        }
    } else {
        result.setRCode(RCode.REQUEST_PARAM_ERR);
    }
    return result;
}

攔截器驗(yàn)證Token

public class TokenInterceptor implements HandlerInterceptor {

    private String secret = "";

    public TokenInterceptor(String secret) {
        this.secret = secret;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 1 如果是OPTIONS ,放行
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            return true;
        }

        boolean requestSend = false;

        try {
            // 請(qǐng)求頭中的 uid
            String headerUid = request.getHeader("uid");
            // 2 獲取Token ,驗(yàn)證
            String headToken = request.getHeader("Authorization");
 
            if (StringUtils.isNotBlank(headToken)) {
                // Bearer。。 Authorization中 Authorization: Bearer <token>
                String jwt = headToken.substring(7);
                // 讀jwt
                JwtUtile jwtUtile = new JwtUtile(secret);
                Claims claims = jwtUtile.readJWT(jwt);

                // 獲取 Jwt中的uid
                Integer jwtUid = claims.get("uid", Integer.class);
                // 對(duì)比 headerUid 和 JwtUid
                if (headerUid.equals(String.valueOf(jwtUid))) {
                    // token 和發(fā)起請(qǐng)求的用戶是同一個(gè), 請(qǐng)求可以被處理
                    requestSend = true;
                }
            }
        } catch (Exception e) {
            requestSend = false;
        }

        // token 沒有通過,需要給vue錯(cuò)誤提示
        if (requestSend == false) {
            // 返回失敗的JSON數(shù)據(jù)給前端
            RespResult result = RespResult.fail();
            result.setRCode(RCode.TOKEN_INVALID);

            // 使用HTTPServletResponse 輸出JSON
            String respJson = JSONObject.toJSONString(result);
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.print(respJson);
            out.flush();
            out.close();
        }

        return requestSend;
    }
}

前端

登錄+存儲(chǔ)Token

userLogin(){
    this.checkPhone();
    this.checkPassword();
    this.checkCode();
    if( this.phoneErr == '' && this.passwordErr == '' & this.codeErr==''){
        //發(fā)起登錄請(qǐng)求
        let param = {
            phone:this.phone,pword:md5(this.password),scode:this.code
        }
        doPost('/v1/user/login',param).then(resp=>{
            if( resp && resp.data.code == 1000){
                //登錄成功,存儲(chǔ)數(shù)據(jù)到localStorage,存的是字符串
                window.localStorage.setItem("token",resp.data.accessToken);
                //把 json對(duì)象轉(zhuǎn)為 string
                window.localStorage.setItem("userinfo", JSON.stringify(resp.data.data));
                //登錄之后,如果name沒有值,需要進(jìn)入到實(shí)名認(rèn)證頁面
                //如果name有值,進(jìn)入到用戶中心
                if(resp.data.data.name == ''){
                    //實(shí)名認(rèn)證
                    this.$router.push({
                        path:'/page/user/realname'
                    })
                } else {
                    //用戶中心
                    this.$router.push({
                        path:'/page/user/usercenter'
                    })
                }
            }
        })
    }
}

前端攔截器

import axios from 'axios'

//創(chuàng)建攔截器
axios.interceptors.request.use(function (config) {

    // 在需要用戶登錄后的操作,在請(qǐng)求的url中加入token
    // 判斷訪問服務(wù)器的url地址, 需要提供身份信息,加入token
    let storageToken = window.localStorage.getItem("token");
    let userinfo = window.localStorage.getItem("userinfo");
    if (storageToken && userinfo) {
        // 添加需要Token驗(yàn)證的url
        if (config.url == '/v1/user/realname' || config.url == '/v1/user/usercenter' ||
            config.url == '/v1/recharge/records' || config.url=='/v1/invest/product') {
            //在header中傳遞token 和一個(gè)userId
            config.headers['Authorization'] = 'Bearer ' + storageToken;
            config.headers['uid'] = JSON.parse(userinfo).uid;
        }
    }
    return config;
}, function (err) {
    console.log("請(qǐng)求錯(cuò)誤" + err);
})

//創(chuàng)建應(yīng)答攔截器,統(tǒng)一對(duì)錯(cuò)誤處理, 后端返回 code > 1000 都是錯(cuò)誤
axios.interceptors.response.use(function (resp) {
    if (resp && resp.data.code > 1000) {
        let code = resp.data.code;
        if (code == 3000) {
            //token無效,重新登錄
            window.location.href = '/page/user/login';
        } else {
            layx.msg(resp.data.msg, {dialogIcon: 'warn', position: 'ct'});
        }
    }
    return resp;
}, function (err) {
    console.log("應(yīng)答攔截器錯(cuò)誤:" + err)
    //回到首頁
    window.location.href = '/';
})

其他請(qǐng)求正常請(qǐng)求就行

axios.get("/v1/user/usercenter").then(resp => {
    if (resp && resp.data.code == 1000) {
    	this.userBaseInfo = resp.data.data;
    }
});

到此這篇關(guān)于SpringBoot+vue+Axios實(shí)現(xiàn)Token令牌的文章就介紹到這了,更多相關(guān)SpringBoot vue實(shí)現(xiàn)Token令牌內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • @scope("prototype") @loadbalanced注解負(fù)載均衡失效問題

    @scope("prototype") @loadbalanced注解負(fù)載均衡失效問題

    這篇文章主要為大家介紹了@scope("prototype") @loadbalanced注解負(fù)載均衡失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • SpringBoot接口限流的實(shí)現(xiàn)方法小結(jié)

    SpringBoot接口限流的實(shí)現(xiàn)方法小結(jié)

    在一個(gè)高并發(fā)系統(tǒng)中對(duì)流量的把控是非常重要的,當(dāng)巨大的流量直接請(qǐng)求到我們的服務(wù)器上沒多久就可能造成接口不可用,不處理的話甚至?xí)斐烧麄€(gè)應(yīng)用不可用,所以我們需要接口限流,本文給大家介紹了SpringBoot接口限流的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2024-10-10
  • 詳解java迭代器模式

    詳解java迭代器模式

    這篇文章主要介紹了java迭代器模式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • java 讀寫Parquet格式的數(shù)據(jù)的示例代碼

    java 讀寫Parquet格式的數(shù)據(jù)的示例代碼

    本篇文章主要介紹了java 讀寫Parquet格式的數(shù)據(jù)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • mybatis動(dòng)態(tài)SQL?if的test寫法及規(guī)則詳解

    mybatis動(dòng)態(tài)SQL?if的test寫法及規(guī)則詳解

    這篇文章主要介紹了mybatis動(dòng)態(tài)SQL?if的test寫法及規(guī)則詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 關(guān)于JVM垃圾回收的java.lang.ref.Finalizer問題

    關(guān)于JVM垃圾回收的java.lang.ref.Finalizer問題

    這篇文章主要介紹了關(guān)于JVM垃圾回收的java.lang.ref.Finalizer問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Spring?Boot最經(jīng)典的20道面試題你都會(huì)了嗎

    Spring?Boot最經(jīng)典的20道面試題你都會(huì)了嗎

    Spring Boot是現(xiàn)代化的Java應(yīng)用程序開發(fā)框架,具有高度的靈活性和可擴(kuò)展性,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot最經(jīng)典的20道面試題,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • SpringBoot自動(dòng)配置原理及案例源碼解析

    SpringBoot自動(dòng)配置原理及案例源碼解析

    這篇文章主要為大家介紹了SpringBoot自動(dòng)配置原理及自動(dòng)配置案例源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java項(xiàng)目中實(shí)現(xiàn)使用traceId跟蹤請(qǐng)求全流程日志

    Java項(xiàng)目中實(shí)現(xiàn)使用traceId跟蹤請(qǐng)求全流程日志

    這篇文章主要介紹了Java項(xiàng)目中實(shí)現(xiàn)使用traceId跟蹤請(qǐng)求全流程日志方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法

    SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法

    在Spring?Cloud中,使用Feign進(jìn)行服務(wù)之間的調(diào)用時(shí),默認(rèn)情況下是不會(huì)傳遞header的,這篇文章給大家介紹SpringCloud服務(wù)之間Feign調(diào)用不會(huì)帶上請(qǐng)求頭header的解決方法,感興趣的朋友一起看看吧
    2024-01-01

最新評(píng)論

郴州市| 如皋市| 寻甸| 开封市| 达日县| 玛沁县| 岚皋县| 海林市| 卢氏县| 隆子县| 洛隆县| 无锡市| 米脂县| 会东县| 竹溪县| 大荔县| 中卫市| 且末县| 哈尔滨市| 金湖县| 扶余县| 凤凰县| 绵阳市| 阿克| 峨眉山市| 布尔津县| 吉安县| 深圳市| 临夏市| 葵青区| 营口市| 柳江县| 榆林市| 福州市| 镇赉县| 鄂托克前旗| 宝丰县| 凤庆县| 松桃| 芒康县| 河北区|