Merge pull request #821 from mgomezch/yesodauthpersist

Decouple YesodAuthPersist from Persistent
This commit is contained in:
Michael Snoyman 2014-09-14 07:30:18 +03:00
commit bec985467f

View File

@ -9,6 +9,7 @@
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-orphans #-}
module Yesod.Auth module Yesod.Auth
( -- * Subsite ( -- * Subsite
@ -18,8 +19,7 @@ module Yesod.Auth
, AuthPlugin (..) , AuthPlugin (..)
, getAuth , getAuth
, YesodAuth (..) , YesodAuth (..)
, YesodAuthPersist , YesodAuthPersist (..)
, AuthEntity
-- * Plugin interface -- * Plugin interface
, Creds (..) , Creds (..)
, setCreds , setCreds
@ -29,8 +29,10 @@ module Yesod.Auth
, loginErrorMessageI , loginErrorMessageI
-- * User functions -- * User functions
, defaultMaybeAuthId , defaultMaybeAuthId
, maybeAuthPair
, maybeAuth , maybeAuth
, requireAuthId , requireAuthId
, requireAuthPair
, requireAuth , requireAuth
-- * Exception -- * Exception
, AuthException (..) , AuthException (..)
@ -162,14 +164,7 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
maybeAuthId :: HandlerT master IO (Maybe (AuthId master)) maybeAuthId :: HandlerT master IO (Maybe (AuthId master))
default maybeAuthId default maybeAuthId
:: ( YesodAuth master :: (YesodAuthPersist master, Typeable (AuthEntity master))
, PersistEntityBackend val ~ YesodPersistBackend master
, Key val ~ AuthId master
, PersistStore (PersistEntityBackend val)
, PersistEntity val
, YesodPersist master
, Typeable val
)
=> HandlerT master IO (Maybe (AuthId master)) => HandlerT master IO (Maybe (AuthId master))
maybeAuthId = defaultMaybeAuthId maybeAuthId = defaultMaybeAuthId
@ -193,40 +188,22 @@ credsKey = "_ID"
-- --
-- Since 1.1.2 -- Since 1.1.2
defaultMaybeAuthId defaultMaybeAuthId
:: ( YesodAuth master :: (YesodAuthPersist master, Typeable (AuthEntity master))
, b ~ YesodPersistBackend master => HandlerT master IO (Maybe (AuthId master))
, b ~ PersistEntityBackend val defaultMaybeAuthId = runMaybeT $ do
, Key val ~ AuthId master s <- MaybeT $ lookupSession credsKey
, PersistStore b aid <- MaybeT $ return $ fromPathPiece s
, PersistEntity val _ <- MaybeT $ cachedAuth aid
, YesodPersist master return aid
, Typeable val
) => HandlerT master IO (Maybe (AuthId master))
defaultMaybeAuthId = do
ms <- lookupSession credsKey
case ms of
Nothing -> return Nothing
Just s ->
case fromPathPiece s of
Nothing -> return Nothing
Just aid -> fmap (fmap entityKey) $ cachedAuth aid
cachedAuth :: ( YesodAuth master cachedAuth
, b ~ YesodPersistBackend master :: (YesodAuthPersist master, Typeable (AuthEntity master))
, b ~ PersistEntityBackend val => AuthId master -> HandlerT master IO (Maybe (AuthEntity master))
, Key val ~ AuthId master cachedAuth
, PersistStore b = fmap unCachedMaybeAuth
, PersistEntity val . cached
, YesodPersist master . fmap CachedMaybeAuth
, Typeable val . getAuthEntity
) => AuthId master -> HandlerT master IO (Maybe (Entity val))
cachedAuth aid = runMaybeT $ do
a <- MaybeT $ fmap unCachedMaybeAuth
$ cached
$ fmap CachedMaybeAuth
$ runDB
$ get aid
return $ Entity aid a
loginErrorMessageI :: (MonadResourceBase m, YesodAuth master) loginErrorMessageI :: (MonadResourceBase m, YesodAuth master)
@ -372,47 +349,65 @@ handlePluginR plugin pieces = do
-- assumes that you are using a Persistent database. -- assumes that you are using a Persistent database.
-- --
-- Since 1.1.0 -- Since 1.1.0
maybeAuth :: ( YesodAuth master maybeAuth :: ( YesodAuthPersist master
, b ~ YesodPersistBackend master , val ~ AuthEntity master
, b ~ PersistEntityBackend val
, Key val ~ AuthId master , Key val ~ AuthId master
, PersistStore b
, PersistEntity val , PersistEntity val
, YesodPersist master
, Typeable val , Typeable val
) => HandlerT master IO (Maybe (Entity val)) ) => HandlerT master IO (Maybe (Entity val))
maybeAuth = runMaybeT $ do maybeAuth = runMaybeT $ do
(aid, ae) <- MaybeT maybeAuthPair
return $ Entity aid ae
-- | Similar to 'maybeAuth', but doesnt assume that you are using a
-- Persistent database.
--
-- Since 1.4.0
maybeAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
=> HandlerT master IO (Maybe (AuthId master, AuthEntity master))
maybeAuthPair = runMaybeT $ do
aid <- MaybeT maybeAuthId aid <- MaybeT maybeAuthId
MaybeT $ cachedAuth aid ae <- MaybeT $ cachedAuth aid
return (aid, ae)
newtype CachedMaybeAuth val = CachedMaybeAuth { unCachedMaybeAuth :: Maybe val } newtype CachedMaybeAuth val = CachedMaybeAuth { unCachedMaybeAuth :: Maybe val }
deriving Typeable deriving Typeable
-- | Constraint which states that the given site is an instance of @YesodAuth@ -- | Class which states that the given site is an instance of @YesodAuth@
-- and that its @AuthId@ is in fact a persistent @Key@ for the given value. -- and that its @AuthId@ is a lookup key for the full user information in
-- This is the common case in Yesod, and means that you can easily look up the -- a @YesodPersist@ database.
-- full informatin on a given user.
-- --
-- Since 1.2.0 -- The default implementation of @getAuthEntity@ assumes that the @AuthId@
type YesodAuthPersist master = -- for the @YesodAuth@ superclass is in fact a persistent @Key@ for the
( YesodAuth master -- given value. This is the common case in Yesod, and means that you can
, YesodPersistBackend master -- easily look up the full information on a given user.
~ PersistEntityBackend (AuthEntity master) --
, Key (AuthEntity master) ~ AuthId master -- Since 1.4.0
, PersistStore (YesodPersistBackend master) class (YesodAuth master, YesodPersist master) => YesodAuthPersist master where
, PersistEntity (AuthEntity master) -- | If the @AuthId@ for a given site is a persistent ID, this will give the
, YesodPersist master -- value for that entity. E.g.:
, Typeable (AuthEntity master) --
) -- > type AuthId MySite = UserId
-- > AuthEntity MySite ~ User
--
-- Since 1.2.0
type AuthEntity master :: *
type AuthEntity master = KeyEntity (AuthId master)
getAuthEntity :: AuthId master -> HandlerT master IO (Maybe (AuthEntity master))
default getAuthEntity
:: ( YesodPersistBackend master
~ PersistEntityBackend (AuthEntity master)
, Key (AuthEntity master) ~ AuthId master
, PersistStore (YesodPersistBackend master)
, PersistEntity (AuthEntity master)
)
=> AuthId master -> HandlerT master IO (Maybe (AuthEntity master))
getAuthEntity = runDB . get
-- | If the @AuthId@ for a given site is a persistent ID, this will give the
-- value for that entity. E.g.:
--
-- > type AuthId MySite = UserId
-- > AuthEntity MySite ~ User
--
-- Since 1.2.0
type AuthEntity master = KeyEntity (AuthId master)
type family KeyEntity key type family KeyEntity key
type instance KeyEntity (Key x) = x type instance KeyEntity (Key x) = x
@ -427,9 +422,22 @@ requireAuthId = maybeAuthId >>= maybe handleAuthLack return
-- authenticated or responds with error 401 if this is an API client (expecting JSON). -- authenticated or responds with error 401 if this is an API client (expecting JSON).
-- --
-- Since 1.1.0 -- Since 1.1.0
requireAuth :: YesodAuthPersist master => HandlerT master IO (Entity (AuthEntity master)) requireAuth :: ( YesodAuthPersist master
, val ~ AuthEntity master
, Key val ~ AuthId master
, PersistEntity val
, Typeable val
) => HandlerT master IO (Entity val)
requireAuth = maybeAuth >>= maybe handleAuthLack return requireAuth = maybeAuth >>= maybe handleAuthLack return
-- | Similar to 'requireAuth', but not tied to Persistent's 'Entity' type.
-- Instead, the 'AuthId' and 'AuthEntity' are returned in a tuple.
--
-- Since 1.4.0
requireAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
=> HandlerT master IO (AuthId master, AuthEntity master)
requireAuthPair = maybeAuthPair >>= maybe handleAuthLack return
handleAuthLack :: Yesod master => HandlerT master IO a handleAuthLack :: Yesod master => HandlerT master IO a
handleAuthLack = do handleAuthLack = do
aj <- acceptsJson aj <- acceptsJson