使用jwt进行token认证

简单说明:最近在搞权限这一块的东西,需要用到jwt进行token认证,才有了如下的demo演示   具体细节可以看gitbug,噗,不是bug是hub  github地址:https://github.com/xuchao6969/jwt_demo  点击前边的gitbug也可以哦

项目是springboot+thymeleaf+mybatis+mysql搭建的

//pom核心依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
//application.yml的核心配置
#token有效期 单位ms
expire_time: 9000000

#token加密secret
token_secret: jwtsecret

token的工具类,包括生成签名、校验、解析等方法

package com.xc.jwt_demo.util;

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


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;


public class JwtTokenUtil {
    
    
    /**
     * 生成签名,过期时间可以从配置文件里读取 具体看方法调用处
     * @param **username**
     * @param **password**
     * @return
     */
    public static String sign(String username, String userId,Long expiretime,String secret) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + expiretime);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("Type", "Jwt");
            header.put("alg", "HS256");
            // 返回token字符串
            return JWT.create()
                    .withHeader(header)
                    .withClaim("loginName", username)
                    .withClaim("userId", userId)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 检验token是否正确
     * @param **token**
     * @return
     */
    public static boolean verify(String token,String secret){
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).build();
            @SuppressWarnings("unused")
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e){
            return false;
        }
    }
    
    /**
     * 从token中获取username信息
     * @param **token**
     * @return
     */
    public static String getUserName(String token){
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("loginName").asString();
        } catch (JWTDecodeException e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * token是否过期 
     * @param token
     */
    public static Boolean checkExpire(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            //获取token过期时间
            Date expiretime = jwt.getExpiresAt();
            String etStr = String.valueOf(expiretime.getTime());
            //获取系统当前时间
            String nowTime = String.valueOf(System.currentTimeMillis());
            //如果系统当前时间超过token过期时间返回false
            if(nowTime.compareTo(etStr)>0){
                return false;
            }
            return true;
        } catch (JWTDecodeException e){
            e.printStackTrace();
        }
        return true;
    }
        
}
JwtTokenUtil.java

 token拦截器,针对所有的请求进行token认证 也是核心

package com.xc.jwt_demo.interceptor;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.xc.jwt_demo.util.JwtTokenUtil;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class);

    //从配置文件application.yml进行加载
    @Value("${token_secret}")
    private String secret;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object)
            throws Exception {
        String str = request.getMethod();
        if (str.equals("OPTIONS")) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }
        response.setCharacterEncoding("utf-8");
        String token = request.getHeader("token");
        if (null != token) {
            //校验token是否过期
            boolean result = JwtTokenUtil.verify(token, secret);
            if (result) {
                logger.info("通过拦截器");
                return true;
            }
        }
        logger.info("认证失败");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("Token不存在或者已失效");
        return false;
    }
}
TokenInterceptor.java

 token拦截器的配置,主要用来配置不需要拦截路径,比如登录...

package com.xc.jwt_demo.config;


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

import com.xc.jwt_demo.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class InterceptorConfig implements WebMvcConfigurer{

    private TokenInterceptor tokenInterceptor;

    public InterceptorConfig(TokenInterceptor tokenInterceptor) {
        this.tokenInterceptor = tokenInterceptor;
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(tokenInterceptor)
                 //拦截所有的请求
                 .addPathPatterns("/**")
                 //放开请求
                 .excludePathPatterns("/sys/test","/sys/login","/sys/doLogin","/js/**");
    }

}
InterceptorConfig.java

 好了,下边的一坨坨代码就是常规的三层业务了,可以参考看一下UserServiceImpl里的生成token 解析token的调用,其他没啥大的价值  另外 我的token是存放在数据库的

package com.xc.jwt_demo.controller;

import java.io.IOException;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xc.jwt_demo.entity.User;
import com.xc.jwt_demo.service.UserService;
import com.xc.jwt_demo.util.JsonUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;


@Controller
@RequestMapping("/sys")
public class LoginController {

    @Resource
    private UserService userService;

    //测试页面
    @RequestMapping("/test")
    public String testThymeleaf(ModelMap model) {
        User user = new User();
        user.setUsername("二叔");
        user.setMobile("911");
        model.addAttribute("user", user);
        return "/viewTest";
    }

    //登录页面
    @RequestMapping("/login")
    public String login(ModelMap model) {
        return "/login";
    }

    @RequestMapping(value = "/doLogin")
    @ResponseBody
    public Integer login(User user) {
        Map<String, Object> resultMap = userService.login(user.getUsername(),user.getPassword());
        Integer code = (Integer) resultMap.get("code");
        return code;
    }

    //使用postman或者restclient进行token测试
    @RequestMapping("/tokenTest")
    public void TokenTest(HttpServletRequest request,HttpServletResponse response) throws IOException {
        String token = request.getHeader("token");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("认证成功 Token是:"+token);
    }
}
LoginController.java
package com.xc.jwt_demo.service;

import java.util.Map;

public interface UserService {

    Map<String, Object> login(String username, String password);
    
}
UserService.java
package com.xc.jwt_demo.service.impl;

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

import com.xc.jwt_demo.dao.UserDao;
import com.xc.jwt_demo.entity.User;
import com.xc.jwt_demo.service.UserService;
import com.xc.jwt_demo.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.springframework.beans.factory.annotation.Value;

@Service("userService")
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    //从配置文件application.yml读取token有效期时间 单位ms
    @Value("${expire_time}")
    private Long expiretime;

    //读取加密的secret
    @Value("${token_secret}")
    private String secret;

    @Autowired
    private UserDao dao;

    @Override
    public Map<String, Object> login(String username,String password) {
        Map<String, Object> map = new HashMap<>();
        User userObj  = dao.getUserByUserName(username);
        //判断用户是否存在
        if(null == userObj){
            map.put("code", 0);//用户不存在
            return map;
        }
        //判断密码是否正确
        if(! password.equals(userObj.getPassword())){
            map.put("code", -1);//密码错误
            return map;
        }
        map.put("code", 1);//用户存在
        String tokenObj = userObj.getToken();
        //用户token不存在就创建token
        if(null == tokenObj || "".equals(tokenObj)){
            String token = JwtTokenUtil.sign(userObj.getUsername(),userObj.getUserId(),expiretime,secret);
            logger.info("-----------创建token-------: "+ token);
            Map<String, Object> paraMap = new HashMap<>();
            paraMap.put("token", token);
            paraMap.put("userId", userObj.getUserId());
            dao.addToken2User(paraMap);
            map.put("token", token);
        }else{
            //取出用户token
            String token = userObj.getToken();
            logger.info("------存在的token-----: "+ token);
            //判断token是否过期    不过期返回,过期     新建token返回并插入数据库
            if(JwtTokenUtil.checkExpire(token)){
                logger.info("-------token存在且有效------: "+ token);
                map.put("token", token);
            }else{
                String tokenStr = JwtTokenUtil.sign(userObj.getUsername(),userObj.getUserId(),expiretime,secret);
                logger.info("------token重新生成-----: "+ tokenStr);
                Map<String, Object> paraMap = new HashMap<>();
                paraMap.put("token", tokenStr);
                paraMap.put("userId", userObj.getUserId());
                dao.addToken2User(paraMap);
                map.put("token", tokenStr);
            }
        }
        map.put("userId", userObj.getUserId());
        map.put("username", userObj.getUsername());
        return map;
    }
    


    
    
}
UserServiceImpl.java
package com.xc.jwt_demo.dao;

import org.apache.ibatis.annotations.Mapper;
import com.xc.jwt_demo.entity.User;
import java.util.Map;

@Mapper
public interface UserDao {
        User getUserByUserName(String username);

        void addToken2User(Map<String, Object> map);
}
UserDao.java
package com.xc.jwt_demo.entity;

import lombok.Data;

@Data
public class User {

    private String userId;
    private String username;
    private String password;
    private String email;
    private String mobile;
    private String status;
    private String createBy;
    private String createTime;
    private String lastUpdateBy;
    private String lastUpdateTime;
    private String department;
    private String realName;
    private String establishVest;
    private String delFlag;
    private String token;

}
User.java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xc.jwt_demo.dao.UserDao">
    <resultMap    id="UserResultMap" type ="com.xc.jwt_demo.entity.User">
        <id property="userId" column="user_id" />
        <result property="username" column="username" />
        <result property="password" column="password" />
        <result property="email" column="email" />
        <result property="mobile" column="mobile" />
        <result property="status" column="status" />
        <result property="createBy" column="create_by" />
        <result property="createTime" column="create_time" />
        <result property="lastUpdateBy" column="last_update_by" />
        <result property="lastUpdateTime" column="last_update_time" />
        <result property="department" column="department" />
        <result property="realName" column="real_name" />
        <result property="establishVest" column="establish_vest" />
        <result property="delFlag" column="del_flag" />
        <result property="token" column="token" />
    </resultMap>

    <sql id="tableName">t_user</sql>

    <update id="addToken2User" parameterType="java.util.Map">
        update <include refid="tableName" /> set token = #{token} where user_id = #{userId}
    </update>

    <select id="getUserByUserName" parameterType="String" resultMap="UserResultMap">
        select * from <include refid="tableName" /> where username = #{username}
    </select>
</mapper>
UserMapper.xml

另外说一点,很重要,在html页面中必须加入<link rel=“shortcut icon” href="#" />  否则会在测试的时候会出现 favicon.ico不存在的问题,从而导致测试失败 vue的话也会有类似的问题

下边是测试

首先不带token访问tokenTest页面  

后台打印

 

然后登陆 获取token

 后台打印

 然后 把token粘到postman或者restClient中  设置好header token再次访问

后台打印

 最终结果

原文地址:https://www.cnblogs.com/xuchao0506/p/13025776.html