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

第二步:定义注解

该注解用于方法或类上,如果类或方法有注解的话,则会被上述拦截器拦截

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

第三步:配置动态绑定

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

第四步:AuthorizationFilterFeature的注册

直接注册到ResourceConfig即可,类似如下代码:

final ResourceConfig rc = new ResourceConfig();
rc.register(AuthorizationFilterFeature.class);
1
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
上次更新: 3 个月前