首页 > 解决方案 > 使 Rho swagger.json 不需要 Auth

问题描述

在尝试使用 Rho lib ( https://github.com/http4s/rho ) 实现自记录 API 时遇到问题 根据要求,我们的路由应受 Auth 中间件 ( https://http4s.org/v0.21/ ) 保护auth/ ),现在 Rho 中间件生成的 swagger.json 也需要身份验证。这是代码:

def startApp(xa:Transactor[IO],appConfig: AppConfig): IO[ExitCode] = {
    val stream = for {
      authService <- Stream.eval(IO(new AuthService(appConfig)))
      routes <- Stream.eval(IO(appRoutes(xa,appConfig,authService.middleware())))
      ...
    } yield exitCode
      ...
  }


  def appRoutes(transactor: Transactor[IO],appConfig: AppConfig,authMiddleware: AuthMiddleware[IO,APIUser]): Kleisli[IO, Request[IO], Response[IO]] = {

    val service = Router[IO](
      baseDataPath -> authMiddleware.apply(
        AuthService.Auth.toService(BootstrapAPI.supportedAPI(transactor, appConfig).toRoutes(swaggerRhoMiddleware))))
  }

有什么方法可以将 swagger.json REST 调用排除在身份验证保护之外?

标签: scalahttp4s

解决方案


我覆盖 SwaggerSupport 并提取 swagger 路线。

import cats.effect.Sync
import cats.implicits.catsSyntaxOptionId
import org.http4s.rho.RhoMiddleware
import org.http4s.rho.RhoRoute
import org.http4s.rho.bits.PathAST.PathMatch
import org.http4s.rho.bits.PathAST.TypedPath
import org.http4s.rho.swagger.DefaultSwaggerFormats
import org.http4s.rho.swagger.SwaggerSupport
import org.http4s.rho.swagger.models._
import shapeless._

import scala.collection.immutable.Seq
import scala.reflect.runtime.universe._

object CustomSwaggerSupport {
  def apply[F[_]: Sync](implicit etag: WeakTypeTag[F[_]]): CustomSwaggerSupport[F] = new CustomSwaggerSupport[F] {}
}

abstract class CustomSwaggerSupport[F[_]](implicit F: Sync[F], etag: WeakTypeTag[F[_]]) extends SwaggerSupport[F] {

  /**
    * Create a RhoMiddleware adding a route to get the Swagger json file
    * representing the full API
    */
  def createRhoMiddlewares: (RhoMiddleware[F], RhoMiddleware[F]) =
    ({ routes => routes }, { routes =>
      lazy val swaggerSpec: Swagger =
        createSwagger(
          swaggerFormats = DefaultSwaggerFormats,
          apiInfo = Info(
            title = "API",
            version = "1.0.0"
          ),
          host = None,
          basePath = "/".some,
          schemes = List(Scheme.HTTP),
          consumes = Nil,
          produces = Nil,
          security = List(SecurityRequirement("bearer", List())),
          securityDefinitions = Map(
            "bearer" -> ApiKeyAuthDefinition("Authorization", In.HEADER)
          ),
          tags = Nil,
          vendorExtensions = Map.empty
        )(
          routes
        )

      lazy val swaggerRoute: Seq[RhoRoute[F, _ <: HList]] =
        createSwaggerRoute(swaggerSpec, TypedPath(PathMatch("swagger.json"))).getRoutes

      swaggerRoute
    })
}

然后我像这样使用它:

  // Create a middleware that will transform RhoService into HttpService with attached Swagger definition
  val (swaggerMiddleware, swaggerRoutes): (RhoMiddleware[IO], RhoMiddleware[IO]) = CustomSwaggerSupport
    .apply[IO]
    .createRhoMiddlewares

  lazy val protectedRoutes: HttpRoutes[IO] = 
    routes.toRoutes(swaggerRoutes) <+> authMiddleware
      .apply(Auth.toService(routes.toRoutes(swaggerMiddleware)))

推荐阅读