Java令牌Token登錄與退出

Java令牌Token登錄與退出

在這裏插入圖片描述

Token

之前的博客已經介紹了各種登錄的方式,現在直接介紹一種現在比較流行的登錄方式,無狀態登錄,只需要客戶端攜帶令牌就能登陸,服務器不再存儲登錄狀態。突然粉絲量爆棚,開心死了,所以抓緊寫一篇硬核代碼,分享給大家,拿來即用的代碼,直接copy即可。
使用之前需要配置一下xml

<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

下面爲Java代碼

package com.caeser.midrug.util;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Maps;

public class JwtHelper {

	private static final String SECRET = "secret";
	
	private static final String ISSURE= "caeser";
	
	public static String getToken(Map<String, String> claims) {
		Algorithm algorithm = Algorithm.HMAC256(SECRET);
		JWTCreator.Builder builder= JWT.create().withIssuer(ISSURE).withExpiresAt(DateUtils.addMinutes(new Date(), 3));
		claims.forEach((k,v) ->builder.withClaim(k, v));
		return builder.sign(algorithm).toString();
	}
	
	public static String getTokenByMinute(Map<String, String> claims,int minute) {
		Algorithm algorithm = Algorithm.HMAC256(SECRET);
		JWTCreator.Builder builder= JWT.create().withIssuer(ISSURE).withExpiresAt(DateUtils.addMinutes(new Date(), minute));
		claims.forEach((k,v) ->builder.withClaim(k, v));
		return builder.sign(algorithm).toString();
	}
	public static String getTokenByHour(Map<String, String> claims,int hour) {
		Algorithm algorithm = Algorithm.HMAC256(SECRET);
		JWTCreator.Builder builder= JWT.create().withIssuer(ISSURE).withExpiresAt(DateUtils.addHours(new Date(), hour));
		claims.forEach((k,v) ->builder.withClaim(k, v));
		return builder.sign(algorithm).toString();
	}
	
	public static Map<String, String> verifyToken(String token){
		Algorithm algorithm = Algorithm.HMAC256(SECRET);
		JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSURE).build();
		DecodedJWT jwt =verifier.verify(token);
		Map<String, Claim> map = jwt.getClaims();
		Map<String, String> resultMap = Maps.newHashMap();
		map.forEach((k,v)->resultMap.put(k,v.asString()));
		return resultMap;
	}
	public static void main(String[] args) {
		
	}
}

解釋

這段代碼其實非常簡單,作爲調包俠的我們,只需要如何設置這個token生成就行了,我自己封裝了一個按分鐘和按小時校驗過期的方法。當獲取到登錄名密碼後,我們校驗通過,就可以對該用戶生成一個token然後返回給前端就行了。

package com.caeser.midrug.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.caeser.midrug.dao.UserAuthDao;
import com.caeser.midrug.dto.Meta;
import com.caeser.midrug.dto.UserAuthExe;
import com.caeser.midrug.entity.UserAuth;
import com.caeser.midrug.enums.UserAuthEnum;
import com.caeser.midrug.service.UserAuthService;
import com.caeser.midrug.util.JwtHelper;
import com.caeser.midrug.util.MD5;
import com.caeser.midrug.util.StaticVariable;

@Service
public class UserAuthServiceImpl implements UserAuthService{
	@Autowired
	UserAuthDao userAuthDao;
	
	@Override
	public UserAuthExe getAuth(String account,String password) {
		UserAuthExe userAuthExe=new UserAuthExe();
		Meta meta=new Meta();
		// 將傳過來的密碼進行MD5加密
		String inputPwd=MD5.getMd5(password);
		// 將賬號與數據庫內匹配
		UserAuth dbAuth=userAuthDao.getPwdByAccount(account);
		if(dbAuth==null) {
			// 如果賬號不存在
			meta.setMsg(UserAuthEnum.ACCOUNT_NONE.getStateInfo());
			meta.setStatus(UserAuthEnum.ACCOUNT_NONE.getState());
		}
		if(dbAuth!=null) {
			// 賬號存在
			// 判斷密碼是否正確
			if(dbAuth.getPassword().equals(inputPwd)) {
				// 密碼正確
				Map<String, String> claim=new HashMap<String, String>();
				// 存儲賬號密碼
				claim.put("account", account);
				claim.put("password", password);
				// 賬號密碼保存到token
				String token=JwtHelper.getTokenByMinute(claim, StaticVariable.LOGINTIME_MINUTE);
				// 將token存儲到返回結果
				userAuthExe.setToken(token);
				// 將用戶信息保存到返回結果
				// 返回賬號
				userAuthExe.setAcccount(account);
				// 返回用戶名
				userAuthExe.setUserName(dbAuth.getUserName());
				// 返回驗證成功信息
				meta.setMsg(UserAuthEnum.SUCCESS.getStateInfo());
				meta.setStatus(UserAuthEnum.SUCCESS.getState());
			}else {
				// 密碼錯誤
				meta.setMsg(UserAuthEnum.PWD_ERROR.getStateInfo());
				meta.setStatus(UserAuthEnum.PWD_ERROR.getState());
			}
		}
		// 存貯返回狀態
		userAuthExe.setMeta(meta);
		return userAuthExe;
	}
}

其中有一串代碼需要大家注意,雖然我的註釋很全了,但是也要分清重點。

String token=JwtHelper.getTokenByMinute(claim, StaticVariable.LOGINTIME_MINUTE);
// 將token存儲到返回結果
userAuthExe.setToken(token);

就是生成並返回給前端的部分。我們再來看前端是如何保存的,我前端使用的Vue框架來寫的。

async loginAction() {
      // 輸入判空
      if (this.loginAcStr === '' || this.loginPsStr === '') {
        return this.$message.error('請輸入密碼')
      }
      var qs = require('qs')
      const {data: res} = await axios.post(this.glAPI + '/home/login', qs.stringify({
        username: this.loginAcStr,
        password: this.loginPsStr
      }))
      var dt = res.result
      if (dt.meta.status !== 1000) {
        if (dt.meta.status === 1001) {
          return this.$message.error('賬號不存在')
        } else {
          return this.$message.error('賬號或密碼錯誤')
        }
      }
      // 密碼正確
      this.$toast('登陸成功')
      // 調用父組件方法獲取登錄信息
      this.$emit('loginGetUserIcon')
      // 保存token
      window.sessionStorage.setItem('token', dt.token)
      // 隱藏
      this.loginDrawerVisible = false
      // 調用父組件方法刷新購物車
      this.$emit('loginRefreshCart')
    }

上述代碼裏window.sessionStorage.setItem('token', dt.token)這句就是保存token,那麼同理註銷也是針對sessionStoragewindow.sessionStorage.clear(),怎麼樣是不是很簡單呀!

分析

在這裏插入圖片描述
爲了讓尋找代碼的小夥伴看到最有用的內容,上面減少了很多廢話,直接上代碼上註釋就好,下面的分析可以理解爲一段可能多餘的話,在以往存儲session或者cookie的時候,可以理解爲一個所有瀏覽器都通用的全局變量,而token就是去除這個全局變量的,將信息保存在了客戶端本地,減輕服務器壓力,網上各種討論哪個好哪個有優勢哪個有缺點,說真的,我還沒有見到實際的業務需求,所有並沒有那麼深刻的體會,也無法給出詳細的解答,就目前而言,我實現了無狀態的登錄,而且可以校驗時間是否過期,這就夠了!

總結

就是如何生成一串字符串,如何保存,然後如何從這段字符串裏分析出時間,然後判定是否過期,然後判定是否有效,就是這樣一個過程,我相信你可能或許不是很理解這個流程,但是你可以先嚐試着使用Token,我一開始是覺得很神奇的,後來想想,其實就是我們參加某次聚會,別人給你發了個工作證明,你憑這個證明就能參加會議了,只不過放到網絡上面確實比較抽象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章