原来这就叫JWT啊

一、JWT是什么?

JWT的全称为json web token。不要把它想得多么高深,其实就是一种生成token的方式。一般我们访问一个系统的流程就是:请求登录接口,该接口会返回一个token,请求其他接口都要带上token,token验证通过才能访问成功,而JWT可以理解为就是生成token的一种机制。

二、JWT怎么用?

1、添加jwt的依赖
<!-- JWT -->
<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>3.4.0</version>
</dependency>
2、新建一个TokenService,用来生成token
@Service
public class TokenService {
	// token过期时间5分钟
	private static final long EXPIRE_TIME = (60 * 1000 * 5);

	public String getToken(User user) {
		return JWT.create()
				// 需要放入token中的信息
				.withAudience(user.getId())
				// 设置token过期时间
				.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME))
				// 用户密码当作密钥
				.sign(Algorithm.HMAC256(user.getPassword()));
	}
}

User类就是一个普通的pojo,这里就不把代码贴出来了。这个getToken方法表示将用户的密码作为密钥,把用户的id放进token中,设置token过期时间为5分钟。

3、新建两个注解,一个注解表示需要验证,另一个表示跳过验证
  • 需要验证:
//可以作用在方法,类和接口上
@Target({ElementType.METHOD, ElementType.TYPE})
//编译器会将SkipToken的信息保存在虚拟机中
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedToken {
	// required 属性默认值为true
	boolean required() default true;
}
  • 跳过验证:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipToken {
	boolean required() default true;
}
4、新建一个AuthInterceptor类,用于拦截请求
public class AuthInterceptor implements HandlerInterceptor {
	@Autowired
	private UserService userService;

	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,Object object) {
		// 从 http 请求头中取出 token
		String token = httpServletRequest.getHeader("token");
		// 只拦截方法,不是方法直接返回true
		if (!(object instanceof HandlerMethod)) {
			return true;
		}
		HandlerMethod handlerMethod = (HandlerMethod) object;
		Method method = handlerMethod.getMethod();
		// 有SkipToken注解的直接跳过认证
		if (method.isAnnotationPresent(SkipToken.class)) {
			SkipToken skipToken = method.getAnnotation(SkipToken.class);
			if (skipToken.required()) {
				return true;
			}
		}
		// 有NeedToken注解的就进行认证
		if (method.isAnnotationPresent(NeedToken.class)) {
			NeedToken needToken = method.getAnnotation(NeedToken.class);
			if (needToken.required()) {
				if (token == null) {
					throw new RuntimeException("无token,请重新登录");
				}
				// 获取 token 中的 userId
				String userId;
				try {
					userId = JWT.decode(token).getAudience().get(0);
				} catch (JWTDecodeException j) {
					throw new RuntimeException("401");
				}
				// 根据userId查询数据库
				User user = userService.findUserById(userId);
				if (user == null) {
					throw new RuntimeException("用户不存在,请重新登录");
				}
				// 用查出来的user的密码去校验token
				JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
				try {
                    // 没发生异常就表示校验通过
					jwtVerifier.verify(token);
				} catch (JWTVerificationException e) {
					throw new RuntimeException("401");
				}
				return true;
			}
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse, Object o,ModelAndView modelAndView) {
	}

	@Override
	public void afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o, Exception e) {
	}
}

这个拦截器的处理逻辑就是:

  • 只拦截方法,如果不是方法,就放行;
  • 如果拦截的方法有@SkipToken注解,放行;
  • 如果拦截的方法有@NeedToken注解,则需要验证token;
  • 取出请求头中的token,拿出token中的userId,根据此userId去数据库查询对应的记录;
  • 再将查出来的user的password去验证token,验证成功则放行;
  • 如果没有@NeedToken也没有@SkipToken注解的,也放行。
5、新建一个InterceptorConfig类,将我们上面写的拦截器配置到spring容器中去
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
	@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor())
                .addPathPatterns("/**");   
    }
    @Bean
    public AuthInterceptor authInterceptor() {
        return new AuthInterceptor();
    }
}
6、在controller中的用法
@RestController
@RequestMapping("api")
public class UserController {
	@Autowired
    private UserService userService;
    @Autowired
    private TokenService tokenService;
   
    @SkipToken
    @PostMapping("/user")
    public JsonResult login(User user){
        User dbUser = userService.findForLogin(user);
        if (dbUser == null){
            return new JsonResult(200, "用户名或密码错误", null);
        } else {
            String token = tokenService.getToken(dbUser);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            resultMap.put("user", dbUser);
            return new JsonResult(200, "登录成功", resultMap);
        }
    }
    
    @NeedToken
    @GetMapping("/getMessage")
    public String getMessage(){
        return "你已通过验证";
    }
    
    @SkipToken
    @GetMapping("/noToken")
    public String noToken() {
    	return "无需token访问";
    }
}

以上就是JWT的用法,其实在实际生产中一般会配合shiro使用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值