java

spring mvc 集成 JWT

spring mvc 集成 jwt

前言

JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。

优点是在分布式系统中,很好地解决了单点登录问题,很容易解决了session共享的问题。
缺点是无法作废已颁布的令牌/不易应对数据过期。

一、pom引入依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

二、工具类

import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;

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

public class JWT {
    private static final String SECRET = "XX#$%()(#*!()!KL<><MQLlwbMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";

    private static final String EXP = "exp";

    private static final String PAYLOAD = "payload";

    //加密,传入一个对象和有效期
    public static <T> String sign(T object, long maxAge) {
        try {
            final JWTSigner signer = new JWTSigner(SECRET);
            final Map<String, Object> claims = new HashMap<String, Object>();
            ObjectMapper mapper = new ObjectMapper();
            String jsonString = mapper.writeValueAsString(object);
            claims.put(PAYLOAD, jsonString);
            claims.put(EXP, System.currentTimeMillis() + maxAge);
            return signer.sign(claims);
        } catch(Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    //解密,传入一个加密后的token字符串和解密后的类型
    public static<T> T unsign(String jwt, Class<T> classT) {
        final JWTVerifier verifier = new JWTVerifier(SECRET);
        try {
            final Map<String,Object> claims= verifier.verify(jwt);
            if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
                long exp = (Long)claims.get(EXP);
                long currentTimeMillis = System.currentTimeMillis();
                if (exp > currentTimeMillis) {
                    String json = (String)claims.get(PAYLOAD);
                    ObjectMapper objectMapper = new ObjectMapper();
                    return objectMapper.readValue(json, classT);
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
}

三、注解接口是否需要验证token

  • IgnoreAuth.java
import java.lang.annotation.*;

/**
 * 忽略Token验证
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2017-03-23 15:44
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreAuth {

}
类方法上接此注解, 不需要验证token, 相反则验证

四、拦截器配置


    public static final String LOGIN_USER_KEY = "LOGIN_USER_KEY";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        IgnoreAuth annotation;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
        }else{
            return true;
        }

        //如果有@IgnoreAuth注解,则不验证token
        if(annotation != null){
            return true;
        }

        //从header中获取token
        String token = request.getHeader("token");
        //如果header中不存在token,则从参数中获取token
        if(StringUtils.isBlank(token)){
            token = request.getParameter("token");
        }

        //token为空
        if(StringUtils.isBlank(token)){
            this.returnResponse(response, "token不能为空");
        }

       ApiMember apiMember = JWT.unsign(token, ApiMember.class);

        if (apiMember == null) {
            returnResponse(response, "token失效");
        }

        String memberId = request.getParameter("memberId");
        if (StringUtils.isNotBlank(memberId)) {
            if (!memberId.equals(apiMember.getId())) {
                returnResponse(response, "登陆信息有误");
            }
        }

        //校验数据库中的用户信息
        YybMember yybMember1 = yybMemberApiService.get(apiMember.getId());
        if (yybMember1 == null) {
            returnResponse(response, "登陆信息有误");
        }


        //设置userId到request里,后续根据userId,获取用户信息
        request.setAttribute(LOGIN_USER_KEY, apiMember);
        return true;
    }
    
    public void returnResponse(HttpServletResponse response, String msg){

        Result result = ResultUtil.error(msg);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(JSON.toJSONString(result));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

用到的Result.java以及ResultUtil.java


public class Result<T>{

    private String code;//状态码

    private String msg;//信息

    private Object data;//数据

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

public class ResultUtil {
    //当正确时返回的值
    public static Result success(Object data){
        Result result = new Result();
        result.setCode("0000");
        result.setMsg("OK");
        result.setData(data);
        return result;
    }

    public static Result success(){
        return success(null);
    }

    //当错误时返回的值
    public static Result error(String code,String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

    //当错误时返回的值
    public static Result error(String msg) {
        Result result = new Result();
        result.setMsg(msg);
        result.setCode("0001");
        return result;
    }
}

三、登陆接口

 /**
     * 登录
     */
    @IgnoreAuth
    @PostMapping("login")
    public Result login(String mobile, String password){
        ApiMember apiMember = new ApiMember();
        apiMember.setMobile(mobile);
        apiMember.setPassword(password);
        //先到数据库验证
        Integer loginId = userService.checkLogin(apiMember);
        if(null == loginId) {
            return ResultUtil.error("用户不存在");
        }
        //给用户jwt加密生成token
        String token = JWT.sign(apiMember, 12L * 60L * 60L * 1000L);
        apiMember.setToken(token);
        return ResultUtil.success(apiMember);
    }

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
文章若有侵权请立即与我联系, 我将及时处理
微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

支付宝扫一扫,向我赞赏

回复

This is just a placeholder img.
Title - Artist
0:00