• Jwt系列2:使用


    一、Jwt在springboot项目中的使用示例代码:

    1、引入pom依赖

    <!--引入JWT依赖,由于是基于Java,所以需要的是java-jwt-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.4.0</version>
    </dependency>

    2、创建两个注解,拦截器通过注释区分是否进行权限拦截

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LoginToken {
        boolean required() default true;
    }
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CheckToken {
        boolean required() default true;
    }

    3、编写JwtUtil工具类

    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    public class JwtUtil {
    
        /**
         * 用户登录成功后生成Jwt
         * 使用Hs256算法  私匙使用用户密码
         *
         * @param ttlMillis jwt过期时间
         * @param user      登录成功的user对象
         * @return
         */
        public static String createJWT(long ttlMillis, User user) {
            //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    
            //生成JWT的时间
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
    
            //创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
            Map<String, Object> claims = new HashMap<String, Object>();
            claims.put("id", user.getId());
            claims.put("username", user.getUsername());
            claims.put("password", user.getPassword());
    
            //生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
            String key = user.getPassword();
    
            //生成签发人
            String subject = user.getUsername();
    
    
    
            //下面就是在为payload添加各种标准声明和私有声明了
            //这里其实就是new一个JwtBuilder,设置jwt的body
            JwtBuilder builder = Jwts.builder()
                    //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
                    .setClaims(claims)
                    //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
                    .setId(UUID.randomUUID().toString())
                    //iat: jwt的签发时间
                    .setIssuedAt(now)
                    //代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
                    .setSubject(subject)
                    //设置签名使用的签名算法和签名使用的秘钥
                    .signWith(signatureAlgorithm, key);
            if (ttlMillis >= 0) {
                long expMillis = nowMillis + ttlMillis;
                Date exp = new Date(expMillis);
                //设置过期时间
                builder.setExpiration(exp);
            }
            return builder.compact();
        }
    
    
        /**
         * Token的解密
         * @param token 加密后的token
         * @param user  用户的对象
         * @return
         */
        public static Claims parseJWT(String token, User user) {
            //签名秘钥,和生成的签名的秘钥一模一样
            String key = user.getPassword();
    
            //得到DefaultJwtParser
            Claims claims = Jwts.parser()
                    //设置签名的秘钥
                    .setSigningKey(key)
                    //设置需要解析的jwt
                    .parseClaimsJws(token).getBody();
            return claims;
        }
    
    
        /**
         * 校验token
         * 在这里可以使用官方的校验,我这里校验的是token中携带的密码于数据库一致的话就校验通过
         * @param token
         * @param user
         * @return
         */
        public static Boolean isVerify(String token, User user) {
            //签名秘钥,和生成的签名的秘钥一模一样
            String key = user.getPassword();
    
            //得到DefaultJwtParser
            Claims claims = Jwts.parser()
                    //设置签名的秘钥
                    .setSigningKey(key)
                    //设置需要解析的jwt
                    .parseClaimsJws(token).getBody();
    
            if (claims.get("password").equals(user.getPassword())) {
                return true;
            }
    
            return false;
        }
    
    }

    4、编写拦截器拦截请求进行权限验证

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.pjb.springbootjjwt.jimisun.CheckToken;
    import com.pjb.springbootjjwt.jimisun.JwtUtil;
    import com.pjb.springbootjjwt.jimisun.LoginToken;
    import com.pjb.springbootjjwt.jimisun.User;
    import com.pjb.springbootjjwt.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    
    
    public class AuthenticationInterceptor implements HandlerInterceptor {
    
        @Autowired
        UserService userService;
    
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
    
            // 从 http 请求头中取出 token
            String token = httpServletRequest.getHeader("token");
            // 如果不是映射到方法直接通过
            if (!(object instanceof HandlerMethod)) {
                return true;
            }
    
            HandlerMethod handlerMethod = (HandlerMethod) object;
            Method method = handlerMethod.getMethod();
            //检查是否有LoginToken注释,有则跳过认证
            if (method.isAnnotationPresent(LoginToken.class)) {
                LoginToken loginToken = method.getAnnotation(LoginToken.class);
                if (loginToken.required()) {
                    return true;
                }
            }
    
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(CheckToken.class)) {
                CheckToken checkToken = method.getAnnotation(CheckToken.class);
                if (checkToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getClaim("id").asString();
                    } catch (JWTDecodeException j) {
                        throw new RuntimeException("访问异常!");
                    }
                    User user = userService.findUserById(userId);
                    if (user == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    Boolean verify = JwtUtil.isVerify(token, user);
                    if (!verify) {
                        throw new RuntimeException("非法访问!");
                    }
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        }
    }

    5、配置拦截器

    import com.pjb.springbootjjwt.interceptor.AuthenticationInterceptor;
    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 {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");   
        }
    
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
    }

    6、在Controller中使用

    import com.alibaba.fastjson.JSONObject;
    import com.pjb.springbootjjwt.annotation.PassToken;
    import com.pjb.springbootjjwt.annotation.UserLoginToken;
    import com.pjb.springbootjjwt.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import javax.validation.Valid;
    import java.util.UUID;
    
    
    @RestController
    @RequestMapping("/api")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        //登录
        @PostMapping("/login")
        @LoginToken
        public Object login(@RequestBody @Valid com.pjb.springbootjjwt.jimisun.User user) {
            JSONObject jsonObject = new JSONObject();
            com.pjb.springbootjjwt.jimisun.User userForBase = userService.findByUsername(user);
            if (userForBase == null) {
                jsonObject.put("message", "登录失败,用户不存在");
                return jsonObject;
            } else {
                if (!userForBase.getPassword().equals(user.getPassword())) {
                    jsonObject.put("message", "登录失败,密码错误");
                    return jsonObject;
                } else {
                    String token = JwtUtil.createJWT(6000000, userForBase);
                    jsonObject.put("token", token);
                    jsonObject.put("user", userForBase);
                    return jsonObject;
                }
            }
        }
    
        //查看个人信息
        @CheckToken
        @GetMapping("/getMessage")
        public String getMessage() {
            return "你已通过验证";
        }
    }
  • 相关阅读:
    JSONObject,JSONArray,Map,String之间转换
    linux下,一个运行中的程序,究竟占用了多少内存
    利用VMware在虚拟机上安装Zookeeper集群
    30岁后职场改变
    Zookeeper客户端 CuratorFramework使用
    oracle 用户与表空间关系
    Docker Rest API使用入门
    docker 远程rest api 访问配置
    Oracle 用户、角色管理简介
    Oracle 参数文件及相关操作介绍
  • 原文地址:https://www.cnblogs.com/XueTing/p/13737008.html
Copyright © 2020-2023  润新知