1:引入jar包
1
2
3
4
5
6<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
2:新建两个接口文件-需要自定义两个注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14package 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; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package 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的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/** * 生成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层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50package 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包
1
2
3
4
5
6<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.1.6.RELEASE</version> </dependency>
6:写AOP层代码进行校验token
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129package 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层进行校验内容请搜索靠谱客的其他文章。
发表评论 取消回复