欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

認(rèn)識Token

對Token有了解可以跳過。

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

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

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

常使用的Token庫是 jjwt

JWT組成

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

JWT 的三個部分依次如下。

Header(頭部)

Payload(負(fù)載)

Signature(簽名)

形如:

eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTE5NzgzNDQsImlhdCI6MTY5MTk3Nzc0NCwianRpIjoiNDEyNjRhNTctYTY0ZC00Y2E5LTljMzMtY2I1MGJmNDc5YjEzIiwicm9sZSI6Iue7j-eQhiIsIm5hbWUiOiLmnY7lm5siLCJ1c2VySWQiOjEwMDF9.t4IrCIs8Y1zLwehouUugeAc-8PBlndpXz5xhibtQIgo

Header

Header: 是一個json對象,存儲元數(shù)據(jù)

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

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

Payload

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

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

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

Private是自己定義的字段

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

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

Signature

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

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

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

JWT簡單使用

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

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

    • 放在請求header 的 Authorization中 Authorization: Bearer

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

  • 客戶端訪問其他api接口, 傳遞token給服務(wù)器, 服務(wù)器認(rèn)證token后,返回給請求的數(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));

    // 存儲用戶數(shù)據(jù)
    Map<String,Object> map = new HashMap();
    map.put("userId",1001);
    map.put("name","李四");
    map.put("role","經(jīng)理");
	// 獲取簽發(fā)時間
    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ā)時間
                                .setId(UUID.randomUUID().toString())				// Token唯一編號
                                .addClaims(map).compact();							// 添加有關(guān)用戶或其他實體的聲明信息
    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對象
        .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 密鑰驗證不一致

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位字符串。存儲在配置文件中
    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)) {
        // 檢查驗證碼是否正確
        if (loginSmsService.checkSmsCode(phone, scode)) {
            // 查找是否存賬號密碼匹配用戶
            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;
}

攔截器驗證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 {
            // 請求頭中的 uid
            String headerUid = request.getHeader("uid");
            // 2 獲取Token ,驗證
            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);
                // 對比 headerUid 和 JwtUid
                if (headerUid.equals(String.valueOf(jwtUid))) {
                    // token 和發(fā)起請求的用戶是同一個, 請求可以被處理
                    requestSend = true;
                }
            }
        } catch (Exception e) {
            requestSend = false;
        }

        // token 沒有通過,需要給vue錯誤提示
        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;
    }
}

前端

登錄+存儲Token

userLogin(){
    this.checkPhone();
    this.checkPassword();
    this.checkCode();
    if( this.phoneErr == '' && this.passwordErr == '' & this.codeErr==''){
        //發(fā)起登錄請求
        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){
                //登錄成功,存儲數(shù)據(jù)到localStorage,存的是字符串
                window.localStorage.setItem("token",resp.data.accessToken);
                //把 json對象轉(zhuǎn)為 string
                window.localStorage.setItem("userinfo", JSON.stringify(resp.data.data));
                //登錄之后,如果name沒有值,需要進(jìn)入到實名認(rèn)證頁面
                //如果name有值,進(jìn)入到用戶中心
                if(resp.data.data.name == ''){
                    //實名認(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) {

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

//創(chuàng)建應(yīng)答攔截器,統(tǒng)一對錯誤處理, 后端返回 code > 1000 都是錯誤
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)答攔截器錯誤:" + err)
    //回到首頁
    window.location.href = '/';
})

其他請求正常請求就行

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

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

相關(guān)文章

  • Spring及Mybatis整合占位符解析失敗問題解決

    Spring及Mybatis整合占位符解析失敗問題解決

    這篇文章主要介紹了Spring及Mybatis整合占位符解析失敗問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • JAVA實現(xiàn)通用日志記錄方法

    JAVA實現(xiàn)通用日志記錄方法

    本篇文章主要介紹了JAVA實現(xiàn)通用日志記錄方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Spring Bean的定義及三種創(chuàng)建方式

    Spring Bean的定義及三種創(chuàng)建方式

    本文主要介紹了Spring容器獲取Bean的9種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • SpringBoot啟動后執(zhí)行方法的五種實現(xiàn)方式

    SpringBoot啟動后執(zhí)行方法的五種實現(xiàn)方式

    本文介紹了SpringBoot中五種在項目啟動后執(zhí)行方法的方式,包括實現(xiàn)CommandLineRunner和ApplicationRunner接口、實現(xiàn)ApplicationListener接口、使用@PostConstruct注解以及實現(xiàn)InitializingBean接口,每種方式都有其特點和適用場景
    2025-02-02
  • SpringBoot-RestTemplate實現(xiàn)調(diào)用第三方API的方式

    SpringBoot-RestTemplate實現(xiàn)調(diào)用第三方API的方式

    RestTemplate?是由?Spring?提供的一個?HTTP?請求工具,它提供了常見的REST請求方案的模版,例如?GET?請求、POST?請求、PUT?請求、DELETE?請求以及一些通用的請求執(zhí)行方法?exchange?以及?execute,下面看下SpringBoot?RestTemplate調(diào)用第三方API的方式
    2022-12-12
  • 詳解Spring Boot 項目中的 parent

    詳解Spring Boot 項目中的 parent

    這篇文章主要介紹了Spring Boot中parent作用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Java中Arrays.sort()方法的比較器詳解

    Java中Arrays.sort()方法的比較器詳解

    這篇文章主要介紹了Java中Arrays.sort()方法的比較器詳解,Arrays.sort(Object[] a)此方法看似沒有要求我們實現(xiàn)比較器,對于基本數(shù)據(jù)類型,String類型確實如此,因為這些類型中已經(jīng)自帶了compareTo()方法,需要的朋友可以參考下
    2023-12-12
  • MyBatis特殊SQL的執(zhí)行實例代碼

    MyBatis特殊SQL的執(zhí)行實例代碼

    這篇文章主要給大家介紹了關(guān)于MyBatis特殊SQL執(zhí)行的相關(guān)資料,文中通過實例代碼和圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-01-01
  • Java自動拆裝箱簡單介紹

    Java自動拆裝箱簡單介紹

    這篇文章主要為大家詳細(xì)介紹了Java自動拆裝箱的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 詳解Java實現(xiàn)負(fù)載均衡的幾種算法代碼

    詳解Java實現(xiàn)負(fù)載均衡的幾種算法代碼

    本篇文章主要介紹了詳解Java實現(xiàn)負(fù)載均衡的幾種算法代碼 ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02

最新評論