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

Play/Scala:如何用orElse组合ActionBuilder实现同接口分角色走不同逻辑

可行实现方案

有两种成熟的实现方式可以满足需求,不需要依赖Play原生没有的orElse Action组合方法:

方案1:单认证Action内做角色分支判断

这是最简洁、性能最优的方案,只走一次认证流程,直接在业务层根据拿到的用户角色做逻辑分发:

// 定义通用JWT认证Action,不提前限制角色范围
val JWTAuthAction: ActionBuilder[Request, AnyContent] = Secure(JWT_CLIENT)(anyContentLarge)

def index = JWTAuthAction.async { req =>
  // 从请求属性中取出play-pac4j注入的认证用户信息
  val userProfile = req.attrs(Pac4jWebKeys.PROFILE).asInstanceOf[CommonProfile]
  userProfile.getRoles match {
    case roles if roles.contains(Authorizers.Role1) => index1(req)
    case roles if roles.contains(Authorizers.Role2) => index2(req)
    case _ => Future.successful(Forbidden("当前用户无访问权限"))
  }
}

def index1(req: Request[AnyContent]) = // 角色1对应的处理逻辑
def index2(req: Request[AnyContent]) = // 角色2对应的处理逻辑

方案2:封装Action的orElse组合工具

如果需要保留独立的角色Action定义(比如逻辑复用时不想耦合判断代码),可以自己封装通用的组合方法,默认将前一个Action返回403作为角色不匹配、尝试下一个Action的触发条件:

/**
 * 多Action备选组合工具,按顺序执行传入的Action,只要返回非403就直接返回结果
 * 所有Action都返回403则最终返回403
 */
def combineActionOrElse(actions: Action[AnyContent]*): Action[AnyContent] = Action.async { req =>
  actions.foldLeft(Future.successful(Option.empty[Result])) { (resultAcc, currentAction) =>
    resultAcc.flatMap {
      case hitResult @ Some(_) => Future.successful(hitResult)
      case None => currentAction(req).map { result =>
        if (result.header.status == 403) None else Some(result)
      }
    }
  }.map(_.getOrElse(Forbidden("无匹配的访问权限")))
}

// 原有按角色定义的Secure Action无需修改
val ACTION_ONE: ActionBuilder[Request, AnyContent] = Secure(JWT_CLIENT,  Authorizers.Role1)(anyContentLarge)
val ACTION_TWO: ActionBuilder[Request, AnyContent] = Secure(JWT_CLIENT,  Authorizers.Role2)(anyContentLarge)

// 直接组合使用即可
def index = combineActionOrElse(
  ACTION_ONE.async(req => index1(req)),
  ACTION_TWO.async(req => index2(req))
)

def index1(req: Request[AnyContent]) = // 角色1对应的处理逻辑
def index2(req: Request[AnyContent]) = // 角色2对应的处理逻辑

注意:如果自定义了play-pac4j认证失败的返回码,需要把工具里的403判断改成你自定义的状态码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:24:03