You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dropwizard 0.8.4中如何用@RolesAllowed注解实现新版本权限控制效果?

在Dropwizard 0.8.4中使用@RolesAllowed实现权限控制

我刚好对Dropwizard 0.8.4的权限控制逻辑有印象,这个版本确实没法像新版本那样直接用Authorizer接口配合@RolesAllowed,不过咱们可以通过自定义过滤器结合JAX-RS的原生机制,实现和新版本一致的权限控制效果,具体步骤如下:

1. 先搞定基础的Basic Auth认证

这部分思路和新版本类似,先完成用户身份认证,同时让用户对象携带角色信息:

1.1 定义带角色的用户类(实现Principal)

这个类用来存储用户的身份标识和对应的权限角色,方便后续权限校验:

import java.security.Principal;
import java.util.Set;

public class User implements Principal {
    private final String username;
    private final Set<String> roles;

    public User(String username, Set<String> roles) {
        this.username = username;
        this.roles = roles;
    }

    @Override
    public String getName() {
        return username;
    }

    public Set<String> getRoles() {
        return roles;
    }
}

1.2 实现Authenticator接口

负责验证用户的账号密码,返回携带角色信息的User对象:

import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
import com.google.common.collect.Sets;
import java.util.Optional;

public class MyAuthenticator implements Authenticator<BasicCredentials, User> {
    @Override
    public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
        // 这里替换成你的实际验证逻辑(比如从数据库查询用户和角色)
        if ("admin".equals(credentials.getUsername()) && "admin123".equals(credentials.getPassword())) {
            return Optional.of(new User("admin", Sets.newHashSet("ADMIN", "USER")));
        }
        if ("user".equals(credentials.getUsername()) && "user123".equals(credentials.getPassword())) {
            return Optional.of(new User("user", Sets.newHashSet("USER")));
        }
        return Optional.empty();
    }
}

1.3 在Application中注册Basic Auth处理器

在你的Application子类的run方法里,把Authenticator绑定到Jetty的安全处理器:

import io.dropwizard.Application;
import io.dropwizard.auth.basic.BasicAuthSecurityHandler;
import io.dropwizard.setup.Environment;

public class MyApp extends Application<MyConfiguration> {
    @Override
    public void run(MyConfiguration config, Environment env) {
        // 注册Basic Auth安全处理器
        env.getApplicationContext().setSecurityHandler(new BasicAuthSecurityHandler(
                new MyAuthenticator(),
                "MyAppRealm" // 自定义Realm名称,随便填写即可
        ));

        // 注册你的资源类
        env.jersey().register(UserResource.class);
    }
}

2. 自定义过滤器处理@RolesAllowed注解

Dropwizard 0.8.4不会自动识别@RolesAllowed注解,所以我们需要写一个ContainerRequestFilter来拦截请求,校验当前用户的角色是否符合注解要求:

2.1 实现权限检查过滤器

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.Priorities;
import javax.ws.rs.Provider;
import javax.annotation.Priority;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;

@Provider
@Priority(Priorities.AUTHORIZATION) // 确保过滤器在认证之后执行
public class RolesAllowedFilter implements ContainerRequestFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        SecurityContext securityContext = requestContext.getSecurityContext();
        // 先判断用户是否已认证
        if (securityContext == null || securityContext.getUserPrincipal() == null) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
            return;
        }

        User currentUser = (User) securityContext.getUserPrincipal();
        // 检查方法上的@RolesAllowed注解
        Method targetMethod = resourceInfo.getResourceMethod();
        checkRoles(targetMethod, currentUser, requestContext);

        // 可选:检查类上的@RolesAllowed注解(如果类上有标记,所有方法都要遵守)
        Class<?> targetClass = resourceInfo.getResourceClass();
        checkRoles(targetClass, currentUser, requestContext);
    }

    private void checkRoles(AnnotatedElement element, User user, ContainerRequestContext context) {
        RolesAllowed rolesAllowed = element.getAnnotation(RolesAllowed.class);
        if (rolesAllowed == null) {
            return;
        }

        String[] allowedRoles = rolesAllowed.value();
        // 校验用户是否拥有至少一个允许的角色
        boolean hasPermission = Arrays.stream(allowedRoles)
                .anyMatch(user.getRoles()::contains);

        if (!hasPermission) {
            context.abortWith(Response.status(Response.Status.FORBIDDEN).build());
        }
    }
}

2.2 注册过滤器到Jersey环境

回到Application的run方法,把这个权限过滤器注册进去:

@Override
public void run(MyConfiguration config, Environment env) {
    // ... 之前的Basic Auth注册代码 ...

    // 注册权限检查过滤器
    env.jersey().register(RolesAllowedFilter.class);
}

3. 在资源类中使用@RolesAllowed

现在就可以像新版本那样,在资源方法或类上标记@RolesAllowed来控制访问权限了:

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.Response;
import javax.annotation.security.RolesAllowed;
import java.util.Arrays;
import java.util.List;

@Path("/users")
public class UserResource {

    @GET
    @RolesAllowed("USER") // 拥有USER或ADMIN角色的用户都能访问
    public List<String> getUsers() {
        return Arrays.asList("user1", "user2", "admin");
    }

    @POST
    @RolesAllowed("ADMIN") // 只有ADMIN角色的用户能访问
    public Response createUser(@FormParam("username") String username) {
        // 这里写创建用户的业务逻辑
        return Response.status(Response.Status.CREATED).entity("用户" + username + "创建成功").build();
    }
}

补充说明

  • 如果你需要更细粒度的权限控制(比如基于资源ID的权限),可以扩展这个过滤器,结合自定义注解来实现。
  • 注意Dropwizard 0.8.4原生的SecurityContext.isUserInRole()方法默认不生效,所以我们直接从User对象中获取角色进行校验是更可靠的方式。

内容的提问来源于stack exchange,提问作者k_liaqat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:13:37