Add auth support for servant-client
This commit is contained in:
parent
970af450dd
commit
ffeeffe745
3 changed files with 57 additions and 0 deletions
|
@ -27,6 +27,7 @@ source-repository head
|
||||||
library
|
library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Servant.Client
|
Servant.Client
|
||||||
|
Servant.Common.Auth
|
||||||
Servant.Common.BaseUrl
|
Servant.Common.BaseUrl
|
||||||
Servant.Common.Req
|
Servant.Common.Req
|
||||||
build-depends:
|
build-depends:
|
||||||
|
@ -34,6 +35,7 @@ library
|
||||||
, aeson
|
, aeson
|
||||||
, attoparsec
|
, attoparsec
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, base64-bytestring
|
||||||
, exceptions
|
, exceptions
|
||||||
, http-api-data >= 0.1 && < 0.3
|
, http-api-data >= 0.1 && < 0.3
|
||||||
, http-client
|
, http-client
|
||||||
|
@ -68,6 +70,7 @@ test-suite spec
|
||||||
, transformers-compat
|
, transformers-compat
|
||||||
, aeson
|
, aeson
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, base64-bytestring
|
||||||
, deepseq
|
, deepseq
|
||||||
, hspec == 2.*
|
, hspec == 2.*
|
||||||
, http-client
|
, http-client
|
||||||
|
|
|
@ -37,6 +37,7 @@ import Network.HTTP.Media
|
||||||
import qualified Network.HTTP.Types as H
|
import qualified Network.HTTP.Types as H
|
||||||
import qualified Network.HTTP.Types.Header as HTTP
|
import qualified Network.HTTP.Types.Header as HTTP
|
||||||
import Servant.API
|
import Servant.API
|
||||||
|
import Servant.Common.Auth
|
||||||
import Servant.Common.BaseUrl
|
import Servant.Common.BaseUrl
|
||||||
import Servant.Common.Req
|
import Servant.Common.Req
|
||||||
|
|
||||||
|
@ -407,6 +408,21 @@ instance HasClient api => HasClient (IsSecure :> api) where
|
||||||
clientWithRoute Proxy req baseurl manager =
|
clientWithRoute Proxy req baseurl manager =
|
||||||
clientWithRoute (Proxy :: Proxy api) req baseurl manager
|
clientWithRoute (Proxy :: Proxy api) req baseurl manager
|
||||||
|
|
||||||
|
instance HasClient api => HasClient (BasicAuth tag realm usr :> api) where
|
||||||
|
type Client (BasicAuth tag realm usr :> api) = BasicAuthData -> Client api
|
||||||
|
|
||||||
|
clientWithRoute Proxy req baseurl manager val =
|
||||||
|
clientWithRoute (Proxy :: Proxy api) (basicAuthReq val req) baseurl manager
|
||||||
|
|
||||||
|
instance ( HasClient api
|
||||||
|
, AuthenticateClientRequest (AuthProtect tag)
|
||||||
|
) => HasClient (AuthProtect tag :> api) where
|
||||||
|
type Client (AuthProtect tag :> api)
|
||||||
|
= ClientAuthType (AuthProtect tag) -> Client api
|
||||||
|
|
||||||
|
clientWithRoute Proxy req baseurl manager val =
|
||||||
|
clientWithRoute (Proxy :: Proxy api) (authReq val req) baseurl manager
|
||||||
|
|
||||||
|
|
||||||
{- Note [Non-Empty Content Types]
|
{- Note [Non-Empty Content Types]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
38
servant-client/src/Servant/Common/Auth.hs
Normal file
38
servant-client/src/Servant/Common/Auth.hs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE TypeSynonymInstances #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
|
-- | Authentication for clients
|
||||||
|
|
||||||
|
module Servant.Common.Auth (
|
||||||
|
AuthenticateClientRequest ( ClientAuthType, authReq )
|
||||||
|
, BasicAuthData (BasicAuthData, username, password)
|
||||||
|
, basicAuthReq
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import Data.ByteString.Base64 (encode)
|
||||||
|
import Data.Monoid ((<>))
|
||||||
|
import Data.Text.Encoding (decodeUtf8)
|
||||||
|
import Servant.Common.Req (addHeader, Req)
|
||||||
|
|
||||||
|
|
||||||
|
-- | A simple datatype to hold data required to decorate a request
|
||||||
|
data BasicAuthData = BasicAuthData { username :: ByteString
|
||||||
|
, password :: ByteString
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Authenticate a request using Basic Authentication
|
||||||
|
basicAuthReq :: BasicAuthData -> Req -> Req
|
||||||
|
basicAuthReq (BasicAuthData user pass) req =
|
||||||
|
let authText = decodeUtf8 ("Basic " <> encode (user <> ":" <> pass))
|
||||||
|
in addHeader "Authorization" authText req
|
||||||
|
|
||||||
|
-- | Class to represent the ability to authenticate a 'Request'
|
||||||
|
-- object. For example, we may add special headers to the 'Request'.
|
||||||
|
class AuthenticateClientRequest a where
|
||||||
|
data ClientAuthType a :: *
|
||||||
|
authReq :: ClientAuthType a -> Req -> Req
|
Loading…
Reference in a new issue