如何在WAI中间件中使用全局状态(Scotty框架场景)
在Scotty中间件中访问全局状态
要解决Scotty中间件访问全局Token状态的问题,核心是让中间件运行在全局状态的StateT上下文里,而非先取出状态再传递给中间件。以下是具体实现方案:
1. 定义全局状态类型
先定义存储有效Token的全局状态结构:
import qualified Data.Set as Set import Data.Text (Text) data AppState = AppState { validTokens :: Set.Set Text -- 存储有效Token的集合 } deriving (Show) -- 初始状态:空Token集合 initialAppState :: AppState initialAppState = AppState Set.empty
2. 实现带状态访问的认证中间件
让中间件直接在StateT AppState IO上下文运行,通过gets获取当前有效Token集合:
import Web.Scotty import Network.Wai (Middleware, requestHeaders) import Network.HTTP.Types.Status (status401) import Network.Wai.Response (responseLBS) import Data.List.Split (splitOn) authMiddleware :: Middleware (StateT AppState IO) authMiddleware app req respond = do -- 从Authorization头解析Bearer Token let maybeToken = lookup "Authorization" (requestHeaders req) >>= parseBearer isValid <- case maybeToken of Nothing -> return False Just token -> do tokens <- gets validTokens return $ Set.member token tokens if isValid then app req respond -- Token有效,继续处理请求 else respond $ responseLBS status401 [] "Unauthorized" -- Token无效,返回401 where parseBearer header = case splitOn " " header of ["Bearer", token] -> Just token _ -> Nothing
3. 在Scotty应用中使用中间件和全局状态
在路由中通过webM操作全局状态(比如登录时添加新Token),并直接注册中间件:
import Control.Monad.State (modify) import Data.Aeson (object, (.=)) app :: ScottyT Text (StateT AppState IO) () app = do -- 注册认证中间件(作用于后续所有路由) middleware authMiddleware -- 登录路由:无需认证,生成并存储Token post "/login" $ do -- 此处添加用户名密码验证逻辑,示例省略 let newToken = "generated-token-123" -- 替换为实际Token生成逻辑 -- 将新Token添加到全局状态 webM $ modify (\s -> s { validTokens = Set.insert newToken (validTokens s) }) json $ object ["token" .= newToken] -- 需要认证的示例路由 get "/protected" $ do html "<h1>Protected Content</h1>"
4. 启动服务器
用runStateT将Scotty应用与初始状态绑定,启动服务器:
main :: IO () main = do _ <- runStateT (scotty 3000 app) initialAppState return ()
原代码问题说明
你尝试先通过webM取出tokensList再传给中间件,但middleware是在Scotty上下文直接调用的,中间件本身可直接访问StateT上下文的状态,无需提前提取。直接在中间件内用gets获取最新全局Token集合,能避免状态同步问题。
内容的提问来源于stack exchange,提问作者KevinT3Hu
相关产品推荐
相关产品推荐

