zoukankan      html  css  js  c++  java
  • 使用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再次访问

    后台打印

     最终结果

  • 相关阅读:
    git
    sublime text
    WIX安装图文并茂简易说明
    C#利用Lambda和Expression实现数据的动态绑定
    Ubuntu/CentOS下如何将普通用户提升到root权限
    虚拟机安装CentOS6.4用“桥接:直接连接到物理网线”不能上网的原因及解决方法
    C#利用lambda表达式将函数作为参数或属性跨类传递
    直接将XML存入到SQL中(SQL2008)
    C# 类中继承接口的属性
    提高开发效率的Visual Studio 2010使用技巧
  • 原文地址:https://www.cnblogs.com/xuchao0506/p/13025776.html
Copyright © 2011-2022 走看看