如何将基本身份验证添加到Scotty中间件? [英] How to add basic auth to Scotty middleware?

查看:64
本文介绍了如何将基本身份验证添加到Scotty中间件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在制作Scotty API,但找不到任何basicAuth实现的示例(Wai Middleware HttpAuth).

I'm currently making a Scotty API and I couldn't find any examples of basicAuth implementations (Wai Middleware HttpAuth).

具体来说,我想向一些端点(即以"admin"开头的端点)添加基本身份验证标头(用户,密码).我已经完成了所有设置,但似乎无法区分哪些端点需要auth,哪些端点不需要auth.我知道我需要使用,但是它使用Yesod,因此我无法将其翻译为Scotty.

Specifically, I want to add basic auth headers (user, pass) to SOME of my endpoints (namely, ones that start with "admin"). I have everything set up, but I can't seem to make the differentiation as to which endpoints require auth and which ones don't. I know I need to use something like this, but it uses Yesod, and I wasn't able to translate it to Scotty.

到目前为止,我有这个:

So far, I have this:

routes :: (App r m) => ScottyT LText m ()
routes = do
  -- middlewares
  middleware $ cors $ const $ Just simpleCorsResourcePolicy
    { corsRequestHeaders = ["Authorization", "Content-Type"]
    , corsMethods = "PUT":"DELETE":simpleMethods
    }
    
  middleware $ basicAuth 
      (\u p -> return $ u == "username" && p == "password") 
      "My Realm" 
  
  -- errors
  defaultHandler $ \str -> do
    status status500
    json str

  -- feature routes
  ItemController.routes
  ItemController.adminRoutes
  
  -- health
  get "/api/health" $
    json True

但是它将身份验证添加到我的所有请求中.我只在其中一些中需要它.

But it adds authentication to all my requests. I only need it in some of them.

非常感谢您!

推荐答案

您可以使用 AuthSettings authIsProtected 字段来定义函数 Request->;IO Bool ,用于确定特定(Wai) Request 是否受基本身份验证的授权.特别是,您可以检查URL路径组件并以此方式确定.

You can use the authIsProtected field of the AuthSettings to define a function Request -> IO Bool that determines if a particular (Wai) Request is subject to authorization by basic authentication. In particular, you can inspect the URL path components and make a determination that way.

不幸的是,这意味着授权检查与Scotty路由完全分开.在您的情况下,此方法效果很好,但可能难以通过Scotty路由进行细粒度的授权控制.

Unfortunately, this means that the check for authorization is completely separated from the Scotty routing. This works fine in your case but can make fine-grained control of authorization by Scotty route difficult.

无论如何, AuthSettings 是您的源中重载的"My Realm" 字符串,根据文档,建议使用定义设置的方式重载的字符串编写如下内容:

Anyway, the AuthSettings are the overloaded "My Realm" string in your source, and according to the documentation, the recommended way of defining the settings is to use the overloaded string to write something like:

authSettings :: AuthSettings
authSettings = "My Realm" { authIsProtected = needsAuth }

这看起来很可怕,但是无论如何, needsAuth 函数将具有签名:

That looks pretty horrible, but anyway, the needsAuth function will have signature:

needsAuth :: Request -> IO Bool

因此它可以检查Wai Request 并在IO中做出有关页面是否首先需要基本身份验证的决定.在 Request 上调用 pathInfo 会为您提供路径组件的列表(没有主机名和查询参数).因此,对于您的需求,以下应该起作用:

so it can inspect the Wai Request and render a decision in IO on whether or not the page needs basic authentication first. Calling pathInfo on the Request gives you a list of path components (no hostname and no query parameters). So, for your needs, the following should work:

needsAuth req = return $ case pathInfo req of
  "admin":_ -> True   -- all admin pages need authentication
  _         -> False  -- everything else is public

请注意,这些是已解析的非查询路径组件,因此,/admin /admin//admin/whatever 甚至是/admin/?q = hello 受保护,但显然/administrator/...不受保护.

Note that these are the parsed non-query path components, so /admin and /admin/ and /admin/whatever and even /admin/?q=hello are protected, but obviously /administrator/... is not.

完整示例:

{-# LANGUAGE OverloadedStrings #-}

import Web.Scotty
import Network.Wai.Middleware.HttpAuth
import Data.Text ()   -- needed for "admin" overloaded string in case
import Network.Wai (Request, pathInfo)

authSettings :: AuthSettings
authSettings = "My Realm" { authIsProtected = needsAuth }

needsAuth :: Request -> IO Bool
needsAuth req = return $ case pathInfo req of
  "admin":_ -> True   -- all admin pages need authentication
  _         -> False  -- everything else is public

main = scotty 3000 $ do
  middleware $ basicAuth (\u p -> return $ u == "username" && p == "password") authSettings
  get "/admin/deletedb" $ do
    html "<h1>Password database erased!</h1>"
  get "/" $ do
    html "<h1>Homepage</h1><p>Please don't <a href=/admin/deletedb>Delete the passwords</a>"

这篇关于如何将基本身份验证添加到Scotty中间件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆