• 基于JWT的Token开发案例


    代码地址如下:
    http://www.demodashi.com/demo/12531.html

    0、准备工作

    0-1运行环境

    1. jdk1.8
    2. maven
    3. 一个能支持以上两者的代码编辑器,作者使用的是IDEA。

    0-2知识储备

    1. 对SpringBoot框架有所了解
    2. 对token的定义有了解
    3. 本案例简单,代码注释较少,有不明白的地方,或者不正确的地方,欢迎联系作者本人或留言。

    1、设计思路

    1-1 项目结构

    项目结构

    本案例模拟用户登录/注册后,服务器返回一个token用于用户后续操作。

    /controller/HelloController.java:测试token的接口
    /controller/UserController.java:用户注册/登录的接口
    /entity/User.java:用户实体类,属性有 用户ID,用户名,密码,邮箱,上次登录时间。
    /repository/UserRepository:实现SpringData接口的数据库操作类,可以很方便的进行CRUD等操作。
    /Reponse/UserResponse.java:接口返回数据的实体类。
    /util/Constants.java:存放常量的工具类。
    /util/JwtUtil.java:Jwt工具类,可以生成、解析Jwt。

    1-2 实现难点

    1. 对Jwt的理解,可以参考http://blog.leapoahead.com/2015/09/06/understanding-jwt/
    2. JwtUtil工具类的开发

    2 具体实现

    2-1 JwtUtil.java

    @Component
    public class JwtUtil {
    
        private static UserRepository userRepository;
    
        @Autowired
        public JwtUtil(UserRepository userRepository) {
            JwtUtil.userRepository = userRepository;
        }
    
        public static final long EXPIRATION_TIME = 3600_000_000L; // 1000 hour
        static final String SECRET = "ThisIsASecret";
        static final String TOKEN_PREFIX = "Bearer";
        static final String HEADER_STRING = "Authorization";
    
        public static String generateToken(String username,Date generateTime) {
            HashMap<String, Object> map = new HashMap<>();
            //可以把任何安全的数据放到map里面
            map.put("username", username);
            map.put("generateTime",generateTime);
            String jwt = Jwts.builder()
                    .setClaims(map)
                    .setExpiration(new Date(generateTime.getTime() + EXPIRATION_TIME))
                    .signWith(SignatureAlgorithm.HS512, SECRET)
                    .compact();
            return jwt;
        }
    
        /**
         * @param token
         * @return
         */
        public static Map<String,Object> validateToken(String token) {
            Map<String,Object> resp = new HashMap<String,Object>();
            if (token != null) {
                // 解析token
                try {
                    Map<String, Object> body = Jwts.parser()
                            .setSigningKey(SECRET)
                            .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                            .getBody();
                    String username = (String) (body.get("username"));
                    Date generateTime = new Date((Long)body.get("generateTime"));
    
                    if(username == null || username.isEmpty()){
                        resp.put("ERR_MSG",Constants.ERR_MSG_USERNAME_EMPTY);
                        return resp;
                    }
                    //账号在别处登录
                    if(userRepository.findByUsername(username).getLastLoginTime().after(generateTime)){
                        resp.put("ERR_MSG",Constants.ERR_MSG_LOGIN_DOU);
                        return resp;
                    }
                    resp.put("username",username);
                    resp.put("generateTime",generateTime);
                    return resp;
                }catch (SignatureException | MalformedJwtException e) {
                    // TODO: handle exception
                    // don't trust the JWT!
                    // jwt 解析错误
                    resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_ERR);
                    return resp;
                } catch (ExpiredJwtException e) {
                    // TODO: handle exception
                    // jwt 已经过期,在设置jwt的时候如果设置了过期时间,这里会自动判断jwt是否已经过期,如果过期则会抛出这个异常,我们可以抓住这个异常并作相关处理。
                    resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EXP);
                    return resp;
                }
            }else {
                resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EMPTY);
                return resp;
            }
        }
    }
    
    

    2.2 UserController.java

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserRepository userRepository;
    
    
        //注册或登录
        @RequestMapping("/login")
        @Transactional
        public UserResponse login(User user){
    
            String username = user.getUsername();
            String password = user.getPassword();
            //TODO  检验参数的完整性
    
            UserResponse userResponse = new UserResponse();
            User tUser = userRepository.findByUsername(username);
            //检验username是否存在
            user.setLastLoginTime(new Date());
            if(tUser!=null){
                //检验密码是否正确
                if(!tUser.getPassword().equals(password)) {
                    userResponse.setErrorNum(Constants.ERR_NUM_PWD_ERR);
                    userResponse.setErrorMsg(Constants.ERR_MSG_PWD_ERR);
                    return userResponse;
                }
                userRepository.updateLastLoginTimeByUserName(user.getLastLoginTime(),username);
    
            }else {
                try {
                    tUser = userRepository.save(user);
                } catch (Exception e) {
                    userResponse.setErrorNum(Constants.ERR_NUM_SERVER_ERR);
                    userResponse.setErrorMsg(Constants.ERR_MSG_SERVER_ERR);
                    return userResponse;
                }
            }
            userResponse.setErrorNum(Constants.ERR_NUM_OK);
            userResponse.setErrorMsg(Constants.ERR_MSG_OK);
            userResponse.setUserName(username);
            userResponse.setUserId(tUser.getId());
            userResponse.setToken(JwtUtil.generateToken(username,user.getLastLoginTime()));
    
            return userResponse;
        }
    }
    
    

    2.3 HelloController.java

    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        public Map login(HttpServletRequest request){
            String token = request.getParameter("token");
            return  JwtUtil.validateToken(token);
        }
    }
    
    

    2.4测试

    登录

    用户登录后,会返回一串token,咱们可以用token进行下一步请求:

    测试token

    当我再次访问登录接口之后,却用旧的token访问测试接口时:

    别处登录

    3 总结

    上面是贴出的主要代码,完整的请下载demo包,有不明白的地方请在下方评论,或者联系邮箱yaoyunxiaoli@163.com。
    我是妖云小离,这是我第二次在Demo大师上发文章,感谢阅读。
    基于JWT的Token开发案例

    代码地址如下:
    http://www.demodashi.com/demo/12531.html

    注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    Hander
    N皇后问题--递归回溯
    NYOJ-571 整数划分(三)
    递归--递推之组合数
    深搜最基础题---全排列And组合数
    递归---NYOJ-176 整数划分(二)和NYOJ-279队花的烦恼二
    递归---NYOJ-90整数划分(一)
    线段树---HDU2795Billboard
    输入输出外挂
    线段树---HDU1394Minimum Inversion Number
  • 原文地址:https://www.cnblogs.com/demodashi/p/8512847.html
Copyright © 2020-2023  润新知