spring boot(10)登錄時token的使用


1.pom.xml

 <!-- jwt 庫相關依賴.  -->
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.7.0</version>
        </dependency>


        <!-- 使用第三方json 解析框架-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.15</version>
        </dependency>

        <!-- 是Apache開源組織提供的用於摘要運算、編碼的包 -->
        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>

        <!-- mobile的模塊可以區分訪問主體是手機、平板、還是PC -->
        <dependency>
            <groupId>org.springframework.mobile</groupId>
            <artifactId>spring-mobile-device</artifactId>
        </dependency>

 2.application.properties

server.context-path=/jwt

jwt.header= Authorization

jwt.secret= mySecret
#設置過期時間
jwt.expiration= 604800

server.tomcat.max-http-header-size=3145728

#logging.level.root=debug

 3.Application.java

package com.guilf;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;

import java.util.ArrayList;
import java.util.List;

@SpringBootApplication
@ServletComponentScan
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }


    /**
     * 1.需要定義一個convert轉換消息的對象
     * 2.創建配置信息,加入配置信息:比如是否需要格式化返回的json
     * 3.converter中添加配置信息
     * 4.convert添加到converters當中
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        // 1.需要定義一個convert轉換消息的對象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

        //2.創建配置信息,加入配置信息:比如是否需要格式化返回的json
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);

        //3.converter中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);

        /**
         *  設置json 返回格式和編碼方式 處理亂碼問題
         */
        List<MediaType> mediaTypeList=new ArrayList<>();
        mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
        fastConverter.setSupportedMediaTypes(mediaTypeList);

        //4.convert添加到converters當中
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);
    }
}

  4.JwtHelper.java

package com.guilf.jwt.utils;

import com.guilf.jwt.domain.LoginInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mobile.device.Device;
import org.springframework.stereotype.Component;

import javax.xml.bind.DatatypeConverter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * jwt及解析jwt的幫助類.
 * 
 */
@Component
public class JwtHelper {


    static final String CLAIM_KEY_USERNAME = "sub";
    static final String CLAIM_KEY_AUDIENCE = "audience";
    static final String CLAIM_KEY_CREATED = "created";

    private static final String AUDIENCE_UNKNOWN = "unknown";
    private static final String AUDIENCE_WEB = "web";
    private static final String AUDIENCE_MOBILE = "mobile";
    private static final String AUDIENCE_TABLET = "tablet";

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public Long getExpiration() {
        return expiration;
    }

    public void setExpiration(Long expiration) {
        this.expiration = expiration;
    }


    public  Claims getClaimsFromToken(String token){
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }


    /**
     * 生成token.
     * @param username 用戶名
     * @param device  org.springframework.mobile.device 設備判斷對象
     * @return
     */
    public  String createJWT(String username, Device device) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, username);
        claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device));
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }


    private  String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 生成token 時間 = 當前時間+ expiration(properties中配置的失效時間)
     * @return
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 通過spring-mobile-device 的device 檢測訪問主體.
     * @param device
     * @return
     */
    private  String generateAudience(Device device) {
        String audience = AUDIENCE_UNKNOWN;
        if (device.isNormal()) {
            audience = AUDIENCE_WEB;//Pc端
        } else if (device.isTablet()) {
            audience = AUDIENCE_TABLET;//Pc端
        } else if (device.isMobile()) {
            audience = AUDIENCE_MOBILE;//平板
        }
        return audience;
    }

    /**
     * 通過token 獲取用戶名.
     * @param authToken
     * @return
     */
    public String getUsernameFromToken(String authToken) {
        String username;
        try {
            final Claims claims = getClaimsFromToken(authToken);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }


    /**
     * 判斷token 失效時間是否到了
     * @param token
     * @return
     */
    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }


    /**
     * 獲取設置的token 失效時間.
     * @param token
     * @return
     */
    public Date getExpirationDateFromToken(String token) {
        Date expiration;
        try {
            final Claims claims = getClaimsFromToken(token);
            expiration = claims.getExpiration();
        } catch (Exception e) {
            expiration = null;
        }
        return expiration;
    }


    /**
     * Token失效校驗.
     * @param token token字符串
     * @param loginInfo 用戶信息
     * @return
     */
    public Boolean validateToken(String token, LoginInfo loginInfo) {
        //1.校驗簽名是否正確
        //2.token是否過期
        //......
        final String username = getUsernameFromToken(token);
        return (
                username.equals(loginInfo.getUsername())
                        && !isTokenExpired(token));
    }
}

  5   MyMD5Util.java

package com.guilf.jwt.utils;

import org.apache.commons.codec.binary.Hex;
import org.springframework.util.StringUtils;

import java.security.MessageDigest;
import java.util.Random;

/**
 * 獲取md5 加密后字符串.
 * 
 */
public class MyMD5Util {

    /**
     * 普通MD5
     *
     * @param password
     * @return
     * 
     */
    public static String MD5(String password) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];

        byte[] md5Bytes = md5.digest(byteArray);

        StringBuffer hexValue = new StringBuffer();

        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }

        return hexValue.toString();
    }

    /**
     * 加鹽MD5
     *
     * @param password
     * @return
     * @author 
     */
    public static String MD5Salt(String password) {
        Random r = new Random();
        StringBuilder sb = new StringBuilder(16);
        sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
        int len = sb.length();
        if (len < 16) {
            for (int i = 0; i < 16 - len; i++) {
                sb.append("0");
            }
        }
        String salt = sb.toString();
        password = md5Hex(password + salt);
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return new String(cs);
    }

    /**
     * 校驗加鹽后是否和原文一致
     *
     * @param password
     * @param md5
     * @return
     * @author 
     */
    public static boolean verify(String password, String md5) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 32; i += 3) {
            cs1[i / 3 * 2] = md5.charAt(i);
            cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
            cs2[i / 3] = md5.charAt(i + 1);
        }
        String salt = new String(cs2);
        return md5Hex(password + salt).equals(new String(cs1));
    }

    /**
     * 獲取十六進制字符串形式的MD5摘要
     */
    private static String md5Hex(String src) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bs = md5.digest(src.getBytes());
            return new String(new Hex().encode(bs));
        } catch (Exception e) {
            return null;
        }
    }

}

  6.登錄進入  JsonWebTokenController.java

package com.hong.jwt.web;

import com.alibaba.fastjson.JSONObject;
import com.hong.jwt.domain.AccessToken;
import com.hong.jwt.domain.LoginInfo;
import com.hong.jwt.neum.UserInfoEnum;
import com.hong.jwt.utils.JwtHelper;
import com.hong.jwt.utils.MyMD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mobile.device.Device;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 */
@RestController
@RequestMapping("/oauth")
public class JsonWebTokenController {

    @Autowired
    private JwtHelper jwtHelper;

    @RequestMapping(value = "/token")
    public JSONObject getAccessToken(HttpServletResponse response, LoginInfo loginInfo, Device device) {
        JSONObject resultMsg = new JSONObject();
        try {
            if (loginInfo.getClientId() == null) {
                resultMsg.put("errcode", 500);
                resultMsg.put("msg", "not is ClientId!");
                return resultMsg;
            }

            //驗證碼校驗在后面章節添加

            //驗證用戶名密碼
            //1.驗證用戶是否存在.
            if (!UserInfoEnum.TEST.getUsername().equals(loginInfo.getUsername()) &&
                    !UserInfoEnum.ADMIN.getUsername().equals(loginInfo.getUsername()) &&
                    !UserInfoEnum.ZHANGSAN.getUsername().equals(loginInfo.getUsername())) {

                resultMsg.put("result_code", 500);
                resultMsg.put("msg", "no user!");
                return resultMsg;
            }
            //2.用戶存在,驗證密碼.
            else {
                // 獲取用戶登錄md5加密后的密碼.
                String loginMD5Password = MyMD5Util.MD5(loginInfo.getPassword());

                // 獲取匹配的密碼.
                String password = null;
                switch (loginInfo.getUsername()) {
                    case "admin":
                        password = UserInfoEnum.ADMIN.getPassword();
                        break;
                    case "test":
                        password = UserInfoEnum.TEST.getPassword();
                        break;
                    case "zhangsan":
                        password = UserInfoEnum.ZHANGSAN.getPassword();
                        break;
                }
                String userMD5Password = MyMD5Util.MD5(password);
                if (!loginMD5Password.equals(userMD5Password)) {
                    resultMsg.put("result_code", 500);
                    resultMsg.put("msg", "password error!");
                    return resultMsg;
                }
            }

            //拼裝accessToken
            String accessToken = jwtHelper.createJWT(loginInfo.getUsername(), device);

            //返回accessToken
            AccessToken accessTokenEntity = new AccessToken();
            accessTokenEntity.setAccessToken(accessToken);
            accessTokenEntity.setExpiresIn(jwtHelper.getExpiration());
            accessTokenEntity.setTokenType("bearer");

            resultMsg.put("result_code", 200);
            resultMsg.put("msg", "success");
            resultMsg.put("token", accessTokenEntity);

            //設置cookie
            Cookie cookie =new Cookie("token",accessToken);
            cookie.setHttpOnly(true);
            //注:Domain為設置Cookie的有效域,Path限制有效路徑
            //1、必須是1-9、a-z、A-Z、. 、- (注意是-不是_)這幾個字符組成
            //2、必須是數字或字母開頭
            //3、必須是數字或字母結尾
            //cookie.setDomain("jwt");
            response.addCookie(cookie);
            return resultMsg;
        } catch (Exception ex) {
            System.out.println(ex);
            resultMsg.put("result_code", 500);
            resultMsg.put("msg", "other error!");
            return resultMsg;
        }
    }
}

  7.在進入其他控制層的時候就會進入過濾器

JwtTokenFilter.java

package com.hong.jwt.filter;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hong.jwt.domain.LoginInfo;
import com.hong.jwt.neum.UserInfoEnum;
import com.hong.jwt.utils.JwtHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 
 */
@WebFilter(filterName = "jwtTokenFilter", urlPatterns = {"/oauth/user"})
public class JwtTokenFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        // String authToken = httpRequest.getHeader("Authorization");

        //從cookie 中獲取jwt token
        Cookie[] cookies = httpRequest.getCookies();
        String authToken =null;
        for (Cookie cookie : cookies) {
            if("token".equals(cookie.getName())){
                authToken = cookie.getValue();
            }
        }
        String username = jwtHelper.getUsernameFromToken(authToken);

        logger.info("checking authentication für user " + username);

        if (username != null) {

            // 這一步通常去數據庫獲取用戶信息
            LoginInfo loginInfo =new LoginInfo();
            switch (username) {
                case "admin":
                    loginInfo.setId(UserInfoEnum.ADMIN.getId());
                    loginInfo.setUsername(UserInfoEnum.ADMIN.getUsername());
                    loginInfo.setPassword(UserInfoEnum.ADMIN.getPassword());
                    break;
                case "test":
                    loginInfo.setId(UserInfoEnum.TEST.getId());
                    loginInfo.setUsername(UserInfoEnum.TEST.getUsername());
                    loginInfo.setPassword(UserInfoEnum.TEST.getPassword());
                    break;
                case "zhangsan":
                    loginInfo.setId(UserInfoEnum.ZHANGSAN.getId());
                    loginInfo.setUsername(UserInfoEnum.ZHANGSAN.getUsername());
                    loginInfo.setPassword(UserInfoEnum.ZHANGSAN.getPassword());
                    break;
            }

            // 驗證 token 有效性.
            if (jwtHelper.validateToken(authToken,loginInfo)) {
               filterChain.doFilter(servletRequest,servletResponse);
            }

            // 驗證token 失敗.
            resultWrite((HttpServletResponse) servletResponse);
            return;
        }else{
            // 驗證token 失敗.
            resultWrite((HttpServletResponse) servletResponse);
            return;
        }
    }

    private void resultWrite(HttpServletResponse servletResponse) throws IOException {
        HttpServletResponse httpResponse = servletResponse;
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json; charset=utf-8");
        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        ObjectMapper mapper = new ObjectMapper();
        JSONObject resultMsg =new JSONObject();
        resultMsg.put("result_code", 500);
        resultMsg.put("msg", "authentication failure!");
        httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
    }

    @Override
    public void destroy() {

    }
}

  

8.UserController.java

package com.hong.jwt.web;

import com.alibaba.fastjson.JSONObject;
import com.hong.jwt.neum.UserInfoEnum;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 
 */
@RestController
public class UserController {


    @PostMapping("/user")
    public JSONObject user(int id){
        JSONObject resultMsg =new JSONObject();
        switch (id) {
            case 1:
               resultMsg.put("username",UserInfoEnum.TEST.getUsername());
                break;
            case 2:
                resultMsg.put("username",UserInfoEnum.ADMIN.getUsername());
                break;
            case 3:
                resultMsg.put("username",UserInfoEnum.ZHANGSAN.getUsername());
                break;
        }

        return resultMsg;
    }
}

  

package com.hong.jwt.filter;
import com.alibaba.fastjson.JSONObject;import com.fasterxml.jackson.databind.ObjectMapper;import com.hong.jwt.domain.LoginInfo;import com.hong.jwt.neum.UserInfoEnum;import com.hong.jwt.utils.JwtHelper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;
/** *  */@WebFilter(filterName = "jwtTokenFilter", urlPatterns = {"/oauth/user"})public class JwtTokenFilter implements Filter {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired    private JwtHelper jwtHelper;
    @Override    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        // String authToken = httpRequest.getHeader("Authorization");
        //從cookie 中獲取jwt token        Cookie[] cookies = httpRequest.getCookies();        String authToken =null;        for (Cookie cookie : cookies) {            if("token".equals(cookie.getName())){                authToken = cookie.getValue();            }        }        String username = jwtHelper.getUsernameFromToken(authToken);
        logger.info("checking authentication für user " + username);
        if (username != null) {
            // 這一步通常去數據庫獲取用戶信息            LoginInfo loginInfo =new LoginInfo();            switch (username) {                case "admin":                    loginInfo.setId(UserInfoEnum.ADMIN.getId());                    loginInfo.setUsername(UserInfoEnum.ADMIN.getUsername());                    loginInfo.setPassword(UserInfoEnum.ADMIN.getPassword());                    break;                case "test":                    loginInfo.setId(UserInfoEnum.TEST.getId());                    loginInfo.setUsername(UserInfoEnum.TEST.getUsername());                    loginInfo.setPassword(UserInfoEnum.TEST.getPassword());                    break;                case "zhangsan":                    loginInfo.setId(UserInfoEnum.ZHANGSAN.getId());                    loginInfo.setUsername(UserInfoEnum.ZHANGSAN.getUsername());                    loginInfo.setPassword(UserInfoEnum.ZHANGSAN.getPassword());                    break;            }
            // 驗證 token 有效性.            if (jwtHelper.validateToken(authToken,loginInfo)) {               filterChain.doFilter(servletRequest,servletResponse);            }
            // 驗證token 失敗.            resultWrite((HttpServletResponse) servletResponse);            return;        }else{            // 驗證token 失敗.            resultWrite((HttpServletResponse) servletResponse);            return;        }    }
    private void resultWrite(HttpServletResponse servletResponse) throws IOException {        HttpServletResponse httpResponse = servletResponse;        httpResponse.setCharacterEncoding("UTF-8");        httpResponse.setContentType("application/json; charset=utf-8");        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        ObjectMapper mapper = new ObjectMapper();        JSONObject resultMsg =new JSONObject();        resultMsg.put("result_code", 500);        resultMsg.put("msg", "authentication failure!");        httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));    }
    @Override    public void destroy() {
    }}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM