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