zl程序教程

您现在的位置是:首页 >  其他

当前栏目

基于JWT的Token开发案例

案例开发 基于 Token JWT
2023-09-11 14:18:03 时间

代码地址如下:
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大师代发,拒绝转载,转载需要作者授权