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

Play Framework 2.8.x:过滤器中检查用户角色并拒绝请求方法

解决Play Framework 2.8.x过滤器中权限检查与请求拒绝问题

嘿,我来帮你搞定这个权限过滤的需求!针对你的两个问题,我一步步给你说明:

1. 如何在过滤器中返回指定状态码拒绝请求

Play Framework里的Result类提供了各种现成的状态码方法,比如forbidden()(403禁止访问)、unauthorized()(401未授权)等。你不需要调用next.apply(rh),直接用CompletableFuture.completedFuture()包装对应的Result就能返回拒绝响应了。

比如要返回403禁止访问的示例:

@Override
public CompletionStage<Result> apply(Function<Http.RequestHeader, CompletionStage<Result>> next, Http.RequestHeader rh) {
    // 先执行权限检查逻辑,不符合就直接返回拒绝结果
    if (!hasPermission(rh)) {
        // 返回403状态码,还可以自定义响应提示文本
        return CompletableFuture.completedFuture(Results.forbidden("抱歉,你没有该页面的访问权限"));
    }
    // 有权限就继续处理后续请求
    return next.apply(rh);
}

常用状态码对应方法:

  • 401未授权:Results.unauthorized()
  • 403禁止访问:Results.forbidden()
  • 404页面不存在:Results.notFound()

2. 如何在过滤器中检查用户角色

要检查用户角色,首先得从请求中获取当前登录用户的信息,具体方式取决于你项目的认证机制,这里给你两种常见场景的实现:

场景一:使用Play内置Security认证

如果你用了Play的Security.Authenticator,可以通过请求属性直接获取认证后的用户:

private boolean hasPermission(Http.RequestHeader rh) {
    // 获取当前认证用户,未登录则直接返回false
    Optional<User> currentUser = rh.attrs().getOptional(Security.AuthenticatedUser.class);
    if (currentUser.isEmpty()) {
        return false;
    }
    User user = currentUser.get();
    // 检查用户角色,这里假设User类有getRoles()方法返回角色列表
    // 可以根据请求路径做精细化权限判断
    return switch (rh.path()) {
        case "/admin/dashboard" -> user.getRoles().contains("ADMIN");
        case "/user/profile" -> user.getRoles().contains("USER");
        default -> true; // 其他页面默认允许访问
    };
}

场景二:自定义Session存储用户信息

如果你的用户ID存在Session里,需要从数据库查询角色信息,可以这样做:

// 假设你有一个UserService用来查询用户信息
@Inject
private UserService userService;

private boolean hasPermission(Http.RequestHeader rh) {
    // 从Session中获取用户ID
    Optional<String> userIdOpt = rh.session().get("userId");
    if (userIdOpt.isEmpty()) {
        return false;
    }
    // 从数据库查询用户详情
    User user = userService.findById(userIdOpt.get());
    if (user == null) {
        return false;
    }
    // 角色检查逻辑和上方一致
    return switch (rh.path()) {
        case "/admin/dashboard" -> user.getRoles().contains("ADMIN");
        case "/user/profile" -> user.getRoles().contains("USER");
        default -> true;
    };
}

完整过滤器示例代码

把上面的逻辑整合到你的PageAccessFilter里,最终代码大概是这样(注意处理异步IO场景):

import play.mvc.*;
import play.libs.concurrent.HttpExecutionContext;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.Optional;
import javax.inject.Inject;

public class PageAccessFilter extends Filter {

    private final UserService userService;
    private final HttpExecutionContext ec;

    @Inject
    public PageAccessFilter(Materializer mat, UserService userService, HttpExecutionContext ec) {
        super(mat);
        this.userService = userService;
        this.ec = ec;
    }

    @Override
    public CompletionStage<Result> apply(Function<Http.RequestHeader, CompletionStage<Result>> next, Http.RequestHeader rh) {
        // 先排除不需要权限检查的路径,比如登录页、静态资源
        if (isPublicPath(rh.path())) {
            return next.apply(rh);
        }

        // 异步执行权限检查(涉及数据库查询时,要用HttpExecutionContext确保线程安全)
        return CompletableFuture.supplyAsync(() -> hasPermission(rh), ec.current())
                .thenApply(hasPerm -> {
                    if (!hasPerm) {
                        return Results.forbidden("抱歉,你没有该页面的访问权限");
                    }
                    return null;
                })
                .thenCompose(result -> {
                    if (result != null) {
                        return CompletableFuture.completedFuture(result);
                    }
                    return next.apply(rh);
                });
    }

    private boolean isPublicPath(String path) {
        return path.startsWith("/login") || path.startsWith("/assets/") || path.equals("/");
    }

    private boolean hasPermission(Http.RequestHeader rh) {
        Optional<String> userIdOpt = rh.session().get("userId");
        if (userIdOpt.isEmpty()) {
            return false;
        }
        User user = userService.findById(userIdOpt.get());
        if (user == null) {
            return false;
        }
        return switch (rh.path()) {
            case "/admin/dashboard" -> user.getRoles().contains("ADMIN");
            case "/user/profile" -> user.getRoles().contains("USER");
            default -> true;
        };
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 18:47:30