jersey实现动态绑定
业务场景
对外提供接口服务时,需要基于token进行拦截。需要拦截指定的请求,根据token判断用户信息有效性。此文不提供token实现方法。
传统实现
传统作法是直接使用一个拦截器,然后拦截所有的请求,通过配置白名单的方式,如果不是白名单的请求则验证token。
还有一种则是在配置拦截器时,指定需要拦截的请求,则不需要配置白名单,也可以实现。
基于jersey的Dynamic binding动态绑定拦截
动态绑定就是一个以动态的方式分配资源方法的筛选器和拦截器。
第一步:定义一个过滤器
/**
* 用户登录过滤器
* @author xiaojun
* @version 2018/12/17
*/
public class AuthorizationFilter implements ContainerRequestFilter {
private TokenService tokenService;
public AuthorizationFilter() {
super();
this.tokenService = TokenService.INSTANCE;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String tokenStr = requestContext.getHeaderString("token");
//token为空时,抛出未授权异常
if (StringUtils.isBlank(tokenStr)) {
throw new ForbiddenException(); //直接抛出异常,此处的异常也可以自定义
}
//验证token
Token token = tokenService.getToken(tokenStr); //这一块根据实际情况验证token
if (token == null) {
throw new ForbiddenException(); //直接抛出异常,此处的异常也可以自定义
}
}
}
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
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
第二步:定义注解
该注解用于方法或类上,如果类或方法有注解的话,则会被上述拦截器拦截
import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 定义注解,判断是否登录,如果把这个注解增加到类或方法上面,说明该类或方法需要登录才可以调用
* @author xiaojun
* @version 2018/12/17
*/
@NameBinding
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface AuthAnnotation {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
第三步:配置动态绑定
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
/**
* 用户登录的一个动态绑定,只要方法上有注解,即会被拦截
* @author xiaojun
* @version 2018/12/17
*/
public class AuthorizationFilterFeature implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
List<Annotation> authzSpecs = new ArrayList<>();
Annotation classAuthzSpec = resourceInfo.getResourceClass().getAnnotation(AuthAnnotation.class); //AuthAnnotation为上述定义的注解
Annotation methodAuthzSpec = resourceInfo.getResourceMethod().getAnnotation(AuthAnnotation.class);
if (classAuthzSpec != null) {
authzSpecs.add(classAuthzSpec);
}
if (methodAuthzSpec != null) {
authzSpecs.add(methodAuthzSpec);
}
if (!authzSpecs.isEmpty()) {
context.register(AuthorizationFilter.class);
}
}
}
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
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
第四步:AuthorizationFilterFeature的注册
直接注册到ResourceConfig即可,类似如下代码:
final ResourceConfig rc = new ResourceConfig();
rc.register(AuthorizationFilterFeature.class);
1
2
2
第五步:简单使用
/**
* 用户管理Api
* @author: xiaojun
* @version: 2018/12/11
*/
@Path("user")
@AuthAnnotation
public class UserApi {
private Logger logger = Logger.getLogger(UserApi.class);
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11