概述
1:引入jar包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2:新建两个接口文件-需要自定义两个注解
package com.noodle.shop.common.VaToken;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//用来跳过验证的PassToken(在controll层上加上这个注解就不会校验token)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
package com.noodle.shop.common.VaToken;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//需要登录才能进行操作的注解UserLoginToken(加上这个注解就会去校验token)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
@Target:注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
@Retention:注解的保留位置
RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
3:在userService中写一个制造token的方法
/**
* 生成token
* @param user
* @return
*/
public String makeToken(VaUserEntity user) {
//这里用的密钥是 iiiii 可根据用户密码啊等等生成,都没关系
//withAudience()存入需要保存在token的信息,这里我把用户ID存入token中
String token="";
Date date = new Date(System.currentTimeMillis()+1000*60*2*24);
token= JWT.create()
.withAudience(user.getId())
.withExpiresAt(date)
.sign(Algorithm.HMAC256("iiiii"));
return token;
}
4:写一个controll层
package com.noodle.shop.controller;
import com.noodle.shop.common.VaToken.UserLoginToken;
import com.noodle.shop.common.util.Message;
import com.noodle.shop.common.util.Messages;
import com.noodle.shop.entity.AddressEnitity;
import com.noodle.shop.entity.VaUserEntity;
import com.noodle.shop.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@Controller
@RequestMapping("/user")
@CrossOrigin
public class Goods {
@Autowired
private UserService userService;
@RequestMapping("/login")
@ResponseBody
public Message login(StringBuilder json) {
//将token返回前端,以后前端每次访问都带着token在请求头上我解析
VaUserEntity user=new VaUserEntity();
user.setId(9);
//调刚刚上面定义的userService中的制造token的方法得到token
String token=userService.makeToken(user);
System.out.printf(token);
return Messages.success(token);
}
@RequestMapping("/index")
@ResponseBody
//有这个玩意就代表这个接口要经过token校验,上面的那个登录接口没得这个玩意就不需要校验,或者加一个 @PassToken 也会跳过校验
@UserLoginToken
public Message indexGoods(AddressEnitity address, VaUserEntity va) {
//address:是用户真实传的数据
//va:是我凭token在切面层解析出来的用户再赛进来的用户数据
System.out.println(address);
System.out.println(va);
return Messages.failed(400,"dsfad");
}
}
5:加入AOP 支持JAR包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
6:写AOP层代码进行校验token
package com.noodle.shop.common.aop;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.noodle.shop.common.Exception.BizException;
import com.noodle.shop.common.VaToken.PassToken;
import com.noodle.shop.common.VaToken.UserLoginToken;
import com.noodle.shop.common.util.*;
import com.noodle.shop.entity.AddressEnitity;
import com.noodle.shop.entity.VaUserEntity;
import com.noodle.shop.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
@Component
@Aspect
@Slf4j
public class ExceptionAop {
@Autowired
private UserService userService;
//定义切面,所有的controller层都会监控
@Pointcut("execution(* com.noodle.shop.controller..*.*(..))")
public void doHander() {
}
@Around("doHander()")
public Object exception(ProceedingJoinPoint joinPoint) {
try {
//进入controller层前
beforePoint(joinPoint);
//放行
Object result = joinPoint.proceed();
//返回数据前
afterPoint(joinPoint, result);
return result;
} catch (BizException e) {
return Messages.failed(e.getCode(), e.getMessage());
} catch (Throwable e) {
return Messages.failed(9999, "系统异常");
}
}
private Boolean beforePoint(ProceedingJoinPoint joinPoint) throws Exception {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
// 从 http 请求头中取出 token
String token = request.getHeader("token");
//得到要进入的是哪个controller方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//检查是否有passtoken注释,有则跳过认证,所以在controller层加了@Passtoken注解,这里我就不校验
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//加了@UserLoginToken注解的我要进行校验
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
// 验证 token 这里的 iiiii 要和上面生成token的密钥一致才能解析成功
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("iiiii")).build();
try {
//验证token
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
//得到这个方法控制器的所有形参
Object[] args = joinPoint.getArgs();
for (Object argItem : args) {
//如果这个控制器方法中有用户这个形参,说明这个控制器需要用户的信息,那么我就把我这里解析出来的userId 赛进这个形参中,那样在控制器那边就能得到我赛的userId了
if (argItem instanceof VaUserEntity) {
VaUserEntity paramVO = (VaUserEntity) argItem;
//paramVO.setPassword("000000");
paramVO.setId(userId);
}
}
return true;
}
}
return true;
}
private void afterPoint(ProceedingJoinPoint joinPoint, Object result) throws Exception {
}
}
使用jwt就这么简单,同时还讲解了怎么在AOP层对参数值进行修改和增加
最后
以上就是激情心情为你收集整理的springboot整合jwt在AOP层进行校验的全部内容,希望文章能够帮你解决springboot整合jwt在AOP层进行校验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复