springboot实现jwt,token认证

JWT简介

JWT的token由三段信息构成的,将这三段信息文本用.连接一起就构成了JWT字符串;

  • Header 头部(包含了令牌的元数据,并且包含签名和或加密算法的类型)
  • Payload 负载
  • Signature 签名/签证
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJwaG9uZSI6IjE1NjgwNzkzNTM5IiwiZXhwIjoxNjE4OTEyNjI1fQ.
RrumX_QyRUBjm92dgHJHuVyiQqg861oDltU1kYjSiVQ

jwt优点

简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,数据量小,传输速度快
自包含(Self-contained):负载中包含了所有用户所需要的信息,避免多次查询数据库
.因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言支持;
不需要在服务端保存会话信息,适用于分布式与微服务;

实现代码

  • 引入pom.xml 依赖
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

jwt工具类

jwt工具类中有三个方法,分别是生成数字签名用于用户首次登陆时发送jwt给客户端;其次是校验方法,用于拦截器拦截所有规则内的url,每个请求都必须带有服务器发送的jwt,经过验证后才放行请求;最后一个获得用户名的方法用于查询密钥,在验证jwt时作为参数传入;


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

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/* *
 * @Author chenlirun
 */
public class JwtUtil {
    
    

    // Token过期时间30分钟
    public static final long EXPIRE_TIME = 30 * 60 * 1000;

    /* *
     * @Author chenlirun
     * <p> 校验token是否正确 </p>
     */
    public static boolean verify(String token, String id,String role String secret) {
    
    
        try {
    
    
            // 设置加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("id", id)
                    .withClaim("role ", role )
                    .build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
    
    
            return false;
        }
    }



    /* *
     * @Author chenlirun
     */
    public static String sign(Integer id, String secret) {
    
    
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带id信息
        return JWT.create()
                .withClaim("id", id)
                .withExpiresAt(date)
                .sign(algorithm);

    }

    /* *
     * @Author lsc
     * <p> 获得用户名 </p>
     */
    public static String getIdByToken(HttpServletRequest request)  {
    
    
        String token = request.getHeader("token");
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("id")
                .asString();
    }

	/**
     * 解析token获取role
     */
    public static String getRoleByToken(HttpServletRequest request)  {
    
    
        String token = request.getHeader("token");
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("role")
                .asString();
    }


}

用户访问限制

  • 自定义注解

限制请求接口是否需要登录,接口以什么身份访问。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginPermission {
    
    

    //登录认证
    boolean login() default true;

    //角色认证
    String role();
    
}
  • 自定义身份信息
public class RolePermission {
    
    

    public static final String User_ADMIN="1" ;

    public static final String USER_GROUP="1,2,3";

    public static final String COMMON="1,2,3";

}

自定义拦截器

拦截请求的接口,认证token携带的信息是否正确。

  • yml中添加秘钥
jwt:
  secret: "abcd"             # 用于生成token的密钥
  expiration: 7200000   # token有效期
  token: Authorization   # http header里token 所在的字段名

自定义拦截器JwtInterceptor,实现HandlerInterceptor接口,每次请求到达之前都会验证token是否有效;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * @Author lsc
 * <p>token验证拦截器 </p>
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {
    
    

    @Value("${jwt.secret}")		//调用实现yml中的配置属性
    private String secret;

      @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        // 从 http 请求头中取出 token
        String token = request.getHeader("token");
        // 如果不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
    
    
            return true;
        }
		  HandlerMethod handlerMethod=(HandlerMethod) handler;
	      Method method = handlerMethod.getMethod();
	      if(method.isAnnotationPresent(RolePermission.class)){
    
    
	          RolePermission annotation = method.getAnnotation(RolePermission.class);
	          if(!annotation.login()){
    
    
	              return true;
	          }
	      }
         if (token != null){
    
    
            int id = JwtUtil.getIdByToken(request);
            String number=JwtUtil.getNumberByToken(request);
            String role=JwtUtil.getRoleByToken(request);
            
            if(method.isAnnotationPresent(RolePermission.class)){
    
    
                RolePermission annotation = method.getAnnotation(RolePermission.class);
                String roleRolePermission = annotation.role();
                if(StringUtils.isBlank(roleRolePermission)){
    
    
                    throw new BaseException("接口权限获取失败");
                }
                int i = roleRolePermission.indexOf(role);
                if(i==-1){
    
    
                    throw new BaseException("用户权限不足");
                }
            }
//            解密token信息
            boolean result = JwtUtil.verify(token,id,number,role,secret);
            if(result){
    
    
                System.out.println("通过拦截器");
                return true;
            }
        }
        return false;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    

    }
}

4.3拦截器配置

拦截器配置中主要定义拦截请求规则,将拦截器注入WebMvcConfigurer;cors跨域处理;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/* *
 * @Author chenlirun
 * <p>拦截器配置 </p>
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    
    

    /* *
     * @Author chenlirun
     * <p> 设置拦截路径 </p>
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/userInfo/login");
//                .excludePathPatterns("/**");
    }
    /* *
     * @Author lsc
     * <p> 将拦截器注入context </p>
     * @Param []
     * @Return com.zszxz.jwt.interceptor.JwtInterceptor
     */
    @Bean
    public JwtInterceptor authenticationInterceptor() {
    
    
        return new JwtInterceptor();
    }

    /* *
     * @Author chenlirun
     * <p>跨域支持 </p>
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    
    
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
                .maxAge(3600 * 24);
    }
}

测试

@SpringBootTest
class DemoApplicationTests {
    
    


    @Value("${jwt.secret}")		//调用实现yml中的配置属性
    private String secret;
    
    @Test
    public void test(){
    
    
        int id=1;
        String role="1";
        String asdf = JwtUtil.sign(id, role, secret);
        System.out.println(asdf);
    }
}

输出结果

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJudW1iZXIiOiIxMjM0NTYiLCJyb2xlIjoiYXNkZiIsImlkIjoxLCJleHAiOjE2MjY4NTc1NTN9.
NWjwBLPky03dUX3GCICKNTGFayqtXPOYJ5GmkE4EEOs

注解使用方式,加到controller 类文件头或者方法体上

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/CSDN_java1005/article/details/115916857