问题描述
在尝试使用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调用排除在Auth保护之外?
解决方法
我覆盖了 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)))