1. 程式人生 > >Java開源生鮮電商平臺-Java後端生成Token架構與設計詳解(源碼可下載)

Java開源生鮮電商平臺-Java後端生成Token架構與設計詳解(源碼可下載)

red 基於 一次 frame service state dha 概述 class

Java開源生鮮電商平臺-Java後端生成Token架構與設計詳解(源碼可下載)

目的:Java開源生鮮電商平臺-Java後端生成Token目的是為了用於校驗客戶端,防止重復提交.

技術選型:用開源的JWT架構。

1.概述:在web項目中,服務端和前端經常需要交互數據,有的時候由於網絡相應慢,客戶端在提交某些敏感數據(比如按照正常的業務邏輯,此份數據只能保存一份)時,如果前端多次點擊提交按鈕會導致提交多份數據,這種情況我們是要防止發生的。

2.解決方法:

①前端處理:在提交之後通過js立即將按鈕隱藏或者置為不可用。

②後端處理:對於每次提交到後臺的數據必須校驗,也就是通過前端攜帶的令牌(一串唯一字符串)與後端校驗來判斷當前數據是否有效。

3.總結:第一種方法相對來說比較簡單,但是安全系數不高,第二種方法從根本上解決了問題,所以我推薦第二種方法。

4.核心代碼:

生成Token的工具類:

  1. /**
  2. * 生成Token的工具類:
  3. */
  4. package red.hearing.eval.modules.token;
  5. import java.security.MessageDigest;
  6. import java.security.NoSuchAlgorithmException;
  7. import java.util.Random;
  8. import sun.misc.BASE64Encoder;
  9. /**
  10. * 生成Token的工具類
  11. * @author zhous
  12. * @since 2018-2-23 13:59:27
  13. *
  14. */
  15. public class TokenProccessor {
  16. private TokenProccessor(){};
  17. private static final TokenProccessor instance = new TokenProccessor();
  18. public static TokenProccessor getInstance() {
  19. return instance;
  20. }
  21. /**
  22. * 生成Token
  23. * @return
  24. */
  25. public String makeToken() {
  26. String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
  27. try {
  28. MessageDigest md = MessageDigest.getInstance("md5");
  29. byte md5[] = md.digest(token.getBytes());
  30. BASE64Encoder encoder = new BASE64Encoder();
  31. return encoder.encode(md5);
  32. } catch (NoSuchAlgorithmException e) {
  33. // TODO Auto-generated catch block
  34. e.printStackTrace();
  35. }
  36. return null;
  37. }
  38. }

Token通用工具類

  1. /**
  2. *
  3. */
  4. package red.hearing.eval.modules.token;
  5. import javax.servlet.http.HttpServletRequest;
  6. import org.apache.commons.lang3.StringUtils;
  7. /**
  8. * Token的工具類
  9. * @author zhous
  10. * @since 2018-2-23 14:01:41
  11. *
  12. */
  13. public class TokenTools {
  14. /**
  15. * 生成token放入session
  16. * @param request
  17. * @param tokenServerkey
  18. */
  19. public static void createToken(HttpServletRequest request,String tokenServerkey){
  20. String token = TokenProccessor.getInstance().makeToken();
  21. request.getSession().setAttribute(tokenServerkey, token);
  22. }
  23. /**
  24. * 移除token
  25. * @param request
  26. * @param tokenServerkey
  27. */
  28. public static void removeToken(HttpServletRequest request,String tokenServerkey){
  29. request.getSession().removeAttribute(tokenServerkey);
  30. }
  31. /**
  32. * 判斷請求參數中的token是否和session中一致
  33. * @param request
  34. * @param tokenClientkey
  35. * @param tokenServerkey
  36. * @return
  37. */
  38. public static boolean judgeTokenIsEqual(HttpServletRequest request,String tokenClientkey,String tokenServerkey){
  39. String token_client = request.getParameter(tokenClientkey);
  40. if(StringUtils.isEmpty(token_client)){
  41. return false;
  42. }
  43. String token_server = (String) request.getSession().getAttribute(tokenServerkey);
  44. if(StringUtils.isEmpty(token_server)){
  45. return false;
  46. }
  47. if(!token_server.equals(token_client)){
  48. return false;
  49. }
  50. return true;
  51. }
  52. }

使用方法:

①在輸出前端頁面的時候調用TokenTools.createToken方法,會把本次生成的token放入session中。

②然後在前端頁面提交數據時從session中獲取token,然後添加到要提交的數據中。

③服務端接受數據後調用judgeTokenIsEqual方法判斷兩個token是否一致,如果不一致則返回,不進行處理。

備註:tokenClientkey和tokenServerkey自定義,調用judgeTokenIsEqual方法時的tokenClientkey一定要與前端頁面的key一致。

基於微信原理JAVA實現線程安全Token驗證-JWT,如果不清楚JWT TOKEN的原理機制,我的上一篇JWT-TOKEN博客有詳細介紹,這篇博文主要是具體實現。

Token主要是用於以作客戶端進行請求的一個令牌,當第一次登錄後,服務器生成一個Token便將此Token返回給客戶端,以後客戶端只需帶上這個Token前來請求數據即可,無需再次帶上密匙。

package com.franz.websocket;
 
import com.franz.common.utils.StringUtils;
import com.franz.weixin.p3.oauth2.util.MD5Util;
import io.jsonwebtoken.*;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.jeecgframework.core.common.service.CommonService;
 
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
 
 
/**
 * OAuthTokenUtils
 * Token管理
 * @author [email protected]
 * @version 2017-08-01
 */
public class OAuthTokenManager {
    private String APP_ID = "";
    private String APP_SECRET = "";
    private String KEY_SING =  ""; //用於存放TOKEN的標誌,Redis
    private LinkedHashMap<string, object=""> pairs = new LinkedHashMap();//封裝json的map
    private CommonService service;
    public static final int MINUTE_TTL = 60*1000;  //millisecond
    public static final int HOURS_TTL = 60*60*1000;  //millisecond
    public static final int DAY_TTL = 12*60*60*1000;  //millisecond
 
 
 
    private OAuthTokenManager() {}
    private static OAuthTokenManager single=null;
    public static OAuthTokenManager getInstance() {
            if (single == null) {
                single = new OAuthTokenManager();
            }
            return single;
        }
 
    public String getKEY_SING() {
        return KEY_SING;
    }
 
    public void setPairs(LinkedHashMap<string, object=""> pairs) {
        this.pairs = pairs;
    }
    public LinkedHashMap<string, object=""> getPairs() {
        return pairs;
    }
 
    public void put(String key, Object value){//向json中添加屬性,在js中訪問,請調用data.map.key
        pairs.put(key, value);
    }
 
    public void remove(String key){
        pairs.remove(key);
    }
 
    /**
     * 總體封裝
     * @param appid
     * @param secret
     * @param logicInterface 回調函數
     * @return
     */
    public String token(String appid,String secret,LogicInterface logicInterface){
        //獲取appid和secret
        this.accessPairs(appid,secret);
        //驗證appid和secretS,獲取對象載體
        Object subject = this.loginAuthentication(logicInterface);
        //生成JWT簽名數據ToKen
        String token = this.createToken(this.generalSubject(subject),this.MINUTE_TTL);
        return token;
    }
 
    public void accessPairs(String APP_ID, String APP_SECRET) {
        this.APP_ID = APP_ID;
        this.APP_SECRET = APP_SECRET;
        //this.KEY_SING = MD5Util.MD5Encode(APP_ID+"_"+APP_SECRET, "UTF-8").toUpperCase();//要用到的時候才用
    }
 
    public Object loginAuthentication(LogicInterface logicInterface){
        if (StringUtils.isNotBlank(APP_ID) && StringUtils.isNotBlank(APP_SECRET)) {
                Map<string, object=""> map = new HashMap<>();
                map.put("APP_ID",APP_ID);
                map.put("APP_SECRET",APP_SECRET);
                if(logicInterface == null || logicInterface.handler(map) == null){
                    return map;
                }else {
                    return logicInterface.handler(map);
                }
        } else {
            return null;
        }
    }
    /**
     * 由字符串生成加密key
     * @return
     */
    public SecretKey generalKey(){
        String stringKey = APP_ID+APP_SECRET;
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    /**
     * 生成subject信息
     * @param obj
     * @return
     */
    public static String generalSubject(Object obj){
        if(obj != null ) {
            JSONObject json = JSONObject.fromObject(obj);
            return json.toString();
        }else{
            return "{}";
        }
 
    }
 
    /**
     * 創建token
     * @param subject
     * @param ttlMillis
     * @return
     * @throws Exception
     */
    public String createToken(String subject, long ttlMillis) {
 
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey key = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setId(APP_ID)
                .setIssuedAt(now)
                .setSubject(subject)
                .signWith(signatureAlgorithm, key);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }
 
    /**
     * 解密token
     * @param token
     * @return
     * @throws Exception
     */
    public Claims validateToken(String token) throws Exception{
        Claims claims = Jwts.parser()
                .setSigningKey(generalKey())
                .parseClaimsJws(token).getBody();
        /*System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());*/
        return claims;
    }
}
import com.ewider.weixin.p3.oauth2.util.MD5Util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
 
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
/**
 * OAuthTokenController
 *
 * @author Franz.ge.倪誌耿
 * @version 2017-08-01
 */
@Scope("prototype")
@Controller
@RequestMapping("/oAuthToken")
public class OAuthToken {
 
    /**
     * 獲取Token
     * @param grant_type
     * @param appid
     * @param secret
     * @return
     */
    @RequestMapping(params = "token",method = RequestMethod.GET)
    @ResponseBody
    public Object token (@RequestParam(value = "grant_type") String grant_type, @RequestParam(value = "appid") String appid,
            @RequestParam(value = "secret") String secret,HttpServletResponse response) {
        Map<string, object=""> map = new HashMap<>();
        switch (grant_type) {
            case "authorization_code" : //授權碼模式(即先登錄獲取code,再獲取token)
                break;
            case "password" : //密碼模式(將用戶名,密碼傳過去,直接獲取token)
                break;
            case "client_credentials" : //客戶端模式(無用戶,用戶向客戶端註冊,然後客戶端以自己的名義向’服務端’獲取資源)
                OAuthTokenManager oAuthTokenManager = OAuthTokenManager.getInstance();
                String token = oAuthTokenManager.token(appid, secret,null);//loginInterface是業務邏輯回掉函數
                //返回Token
                map.put("access_token",token);
                map.put("expires_in",OAuthTokenManager.MINUTE_TTL/1000);
                break;
            case "implicit" : //簡化模式(在redirect_uri 的Hash傳遞token; Auth客戶端運行在瀏覽器中,如JS,Flash)
                break;
            case "refresh_token" : //刷新access_token
                break;
        }
 
        return map;
    }
 
    @RequestMapping(params = "loginAuth2",method = RequestMethod.GET)
    @ResponseBody
    public Object loginAuth2 (HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "accessToken") String accessToken ){
        Map<string, object=""> map = new HashMap<>();
        //COOKIE不存在:解析驗證正確性
        try {
                OAuthTokenManager oAuthTokenManager = OAuthTokenManager.getInstance();
                Claims claims = oAuthTokenManager.validateToken(accessToken);
                if (claims != null ) {
                    map.put("state","success");
                    map.put("loginAuth","采用Token登錄");
                    int validMillis = (int)(claims.getExpiration().getTime()-System.currentTimeMillis());
                    if(validMillis > 0) {
                        //交給容器管理,可以存放redis,這裡模擬是cookie
                        Cookie cookie = new Cookie(MD5Util.MD5Encode("MD5SING", "UTF-8").toUpperCase(), accessToken);
                        cookie.setMaxAge(validMillis/1000);
                        response.addCookie(cookie);
                    }
 
                }else{
                    map.put("state","fail");
                }
            }catch (MalformedJwtException | SignatureException e){
                     map.put("state","signature");//改造簽名,或者無效的Token
                     map.put("loginAuth","該Token無效");//改造簽名,或者無效的Token
            }catch (ExpiredJwtException e){
                     map.put("state","expired");//改造簽名,或者無效的Token
                     map.put("loginAuth","Token已經過時");
            }catch (Exception e) {
            e.printStackTrace();
            map.put("state","fail");
            }
            return map;
    }
 
    @RequestMapping(params = "index",method = RequestMethod.GET)
    @ResponseBody
    public Object index (HttpServletRequest request, HttpServletResponse response){
        Map<string, object=""> map = new HashMap<>();
        //從COOKIE中查找,模擬訪問,可以集成容器管理
        Cookie[] cookies = request.getCookies();
        if (cookies!=null) {
            for (int i = cookies.length-1; i >= 0; i--) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals(MD5Util.MD5Encode("MD5SING", "UTF-8").toUpperCase())) {
                    //跳過登陸
                    map.put("index","采用Redis登錄");
                    return map;
                }
            }
        }
        map.put("index","你的Token已經銷毀");
        return map;
    }
 
}
        <dependency>
            <groupid>io.jsonwebtoken</groupid>
           <artifactid>jjwt</artifactid>
            <version>0.7.0</version>
        </dependency>

目錄:
1.Java開源生鮮電商平臺-系統簡介 https://www.cnblogs.com/jurendage/p/9012355.html
2.Java開源生鮮電商平臺-系統架構與技術選型(源碼可下載) https://www.cnblogs.com/jurendage/p/9012922.html
3.Java開源生鮮電商平臺-盈利模式詳解(源碼可下載) https://www.cnblogs.com/jurendage/p/9016411.html
4.Java開源生鮮電商平臺-用戶表的設計(源碼可下載) https://www.cnblogs.com/jurendage/p/9017912.html
5.Java開源生鮮電商平臺-商品表的設計(源碼可下載) https://www.cnblogs.com/jurendage/p/9022917.html
6.Java開源生鮮電商平臺-訂單表的設計(源碼可下載) https://www.cnblogs.com/jurendage/p/9029467.html
7.Java開源生鮮電商平臺-支付模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9034444.html
8.Java開源生鮮電商平臺-購物車模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9039195.html
9.Java開源生鮮電商平臺-推薦系統模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9044283.html
10.Java開源生鮮電商平臺-財務系統模塊的設計與架構(源碼可下載)https://www.cnblogs.com/jurendage/p/9049318.html
11.Java開源生鮮電商平臺-賬單模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9053417.html
12.Java開源生鮮電商平臺-提現模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9053523.html
13.Java開源生鮮電商平臺-訂單抽成模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9059304.html
14.Java開源生鮮電商平臺-搜索模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9062649.html
15.Java開源生鮮電商平臺-售後模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9066307.html
16.Java開源生鮮電商平臺-監控模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9070442.html
17.Java開源生鮮電商平臺-異常模塊的設計與架構(源碼可下載)https://www.cnblogs.com/jurendage/p/9075219.html
18.Java開源生鮮電商平臺-性能優化以及服務器優化的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9081062.html
19.Java開源生鮮電商平臺-安全設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9087581.html
20.Java開源生鮮電商平臺-優惠券設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9091587.html
21.Java開源生鮮電商平臺-通知模塊設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9095078.html
22.Java開源生鮮電商平臺-團購模塊設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9098368.html
23.Java開源生鮮電商平臺-服務器部署設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9103339.html
24.Java開源生鮮電商平臺-系統報表設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9108863.html
25.Java開源生鮮電商平臺-源碼地址公布與思考和建議 https://www.cnblogs.com/jurendage/p/9114796.html
26.Java開源生鮮電商平臺-RBAC系統權限的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9120168.html
27.Java開源生鮮電商平臺-物流配送的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9124947.html
28.Java開源生鮮電商平臺-庫存管理設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9130455.html
29.Java開源生鮮電商平臺-銷售管理設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9131557.html
30.Java開源生鮮電商平臺-電商促銷業務分析設計與系統架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9137815.html
31.Java開源生鮮電商平臺-一次代碼重構的實戰案例(源碼可下載) https://www.cnblogs.com/jurendage/p/9143105.html
32.Java開源生鮮電商平臺-商品價格的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9148906.html
33.Java開源生鮮電商平臺-定時器,定時任務quartz的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9153835.html
34.Java開源生鮮電商平臺-高並發的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9159020.html
35.Java開源生鮮電商平臺-技術方案與文檔下載(源碼可下載) https://www.cnblogs.com/jurendage/p/9162190.html
36.Java開源生鮮電商平臺-積分,優惠券,會員折扣,簽到、預售、拼團、砍價、秒殺及抽獎等促銷模塊架構設計(源碼可下載) https://www.cnblogs.com/jurendage/p/9165594.html
37.Java開源生鮮電商平臺-供應鏈模塊的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9171467.html
38.Java開源生鮮電商平臺-會員積分系統的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9176010.html
39.Java開源生鮮電商平臺-redis緩存在商品中的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9181380.html
40.Java開源生鮮電商平臺-商品無限極目錄的設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9185990.html
41.Java開源生鮮電商平臺-物流動態費率、免運費和固定運費設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9189736.html
42.Java開源生鮮電商平臺-商品的spu和sku數據結構設計與架構(源碼可下載) https://www.cnblogs.com/jurendage/p/9194551.html
43.Java開源生鮮電商平臺-你應該保留的一些學習態度與學習方法(源碼可下載) https://www.cnblogs.com/jurendage/p/9197096.html

Java開源生鮮電商平臺-Java後端生成Token架構與設計詳解(源碼可下載),如果需要下載的話,可以在我的github下面進行下載。

https://github.com/137071249/

群號:168096884

Java開源生鮮電商平臺-Java後端生成Token架構與設計詳解(源碼可下載)