Created
June 4, 2017 06:23
-
-
Save naoto-ogawa/0a5a137e044b2cc4a00d9e7d173c98ad to your computer and use it in GitHub Desktop.
Token Authentication with Servant with IO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
https://jerrington.me/posts/2016-06-18-token-authentication-with-servant.html | |
https://github.com/tsani/servant-otoke/blob/815c0aef69c3a0aac8b0f664a8122c8d2a490182/src/Main.hs | |
Add IO points | |
-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE MultiParamTypeClasses #-} | |
{-# LANGUAGE OverloadedStrings #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
module OToken where | |
import qualified Data.ByteString as BS | |
import qualified Data.Text as T | |
import Network.Wai ( Application, requestHeaders ) | |
import Network.Wai.Handler.Warp ( run ) | |
import Servant | |
import Servant.Server.Internal.RoutingApplication | |
import Control.Monad.Base -- for IO | |
data Otoke | |
instance HasServer sublayout context => HasServer (Otoke :> sublayout) context where | |
type ServerT (Otoke :> sublayout) m = () -> ServerT sublayout m | |
route Proxy context subserver = | |
route (Proxy :: Proxy sublayout) context (addAuthCheck subserver go) where | |
-- withRequest :: (Network.Wai.Internal.Request -> DelayedIO ()) -> DelayedIO () | |
-- go :: DelayedIO () | |
go = withRequest $ \req -> do | |
-- ***** IO ***** | |
-- liftBase :: IO () -> DelayedIO () | |
liftBase $ putStrLn "withRequest" | |
-- ***** IO ***** | |
case parseHeaderMaybe =<< lookup "Authorization" (requestHeaders req) of | |
Nothing -> delayedFail err401 | |
Just h -> do | |
-- ***** IO ***** | |
-- liftBase :: IO () -> DelayedIO () | |
liftBase $ putStrLn $ "value=" ++ (T.unpack h) | |
-- ***** IO ***** | |
if h `elem` pws then pure () else delayedFail err401 | |
pws :: [T.Text] | |
pws = ("oToke " `T.append`) <$> [ "hello" , "world" ] | |
parseHeaderMaybe :: FromHttpApiData a => BS.ByteString -> Maybe a | |
parseHeaderMaybe = eitherMaybe . parseHeader where | |
eitherMaybe :: Either e a -> Maybe a | |
eitherMaybe e = case e of | |
Left _ -> Nothing | |
Right x -> Just x | |
type MyAPI = "unprotected" :> Get '[PlainText] String | |
:<|> "protected" :> Otoke :> Get '[PlainText] String | |
myServer :: Server MyAPI | |
myServer = pure "not secret" :<|> const (pure "secret") | |
app :: Application | |
app = serve (Proxy :: Proxy MyAPI) myServer | |
main :: IO () | |
main = run 8081 app |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment