Facebook support in auth
This commit is contained in:
parent
a8e6485e46
commit
f7f42cad1d
@ -38,6 +38,7 @@ module Yesod.Helpers.Auth
|
|||||||
|
|
||||||
import qualified Web.Authenticate.Rpxnow as Rpxnow
|
import qualified Web.Authenticate.Rpxnow as Rpxnow
|
||||||
import qualified Web.Authenticate.OpenId as OpenId
|
import qualified Web.Authenticate.OpenId as OpenId
|
||||||
|
import qualified Web.Authenticate.Facebook as Facebook
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ import System.IO
|
|||||||
import Control.Monad.Attempt
|
import Control.Monad.Attempt
|
||||||
import Data.Monoid (mempty)
|
import Data.Monoid (mempty)
|
||||||
import Data.ByteString.Lazy.UTF8 (fromString)
|
import Data.ByteString.Lazy.UTF8 (fromString)
|
||||||
|
import Data.Object
|
||||||
|
|
||||||
class Yesod master => YesodAuth master where
|
class Yesod master => YesodAuth master where
|
||||||
-- | Default destination on successful login or logout, if no other
|
-- | Default destination on successful login or logout, if no other
|
||||||
@ -82,10 +84,12 @@ data Auth = Auth
|
|||||||
{ authIsOpenIdEnabled :: Bool
|
{ authIsOpenIdEnabled :: Bool
|
||||||
, authRpxnowApiKey :: Maybe String
|
, authRpxnowApiKey :: Maybe String
|
||||||
, authEmailSettings :: Maybe AuthEmailSettings
|
, authEmailSettings :: Maybe AuthEmailSettings
|
||||||
|
, authFacebook :: Maybe (String, String) -- ^ client id and secret
|
||||||
|
, authFacebookPerms :: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Which subsystem authenticated the user.
|
-- | Which subsystem authenticated the user.
|
||||||
data AuthType = AuthOpenId | AuthRpxnow | AuthEmail
|
data AuthType = AuthOpenId | AuthRpxnow | AuthEmail | AuthFacebook
|
||||||
deriving (Show, Read, Eq)
|
deriving (Show, Read, Eq)
|
||||||
|
|
||||||
type Email = String
|
type Email = String
|
||||||
@ -117,6 +121,7 @@ data Creds = Creds
|
|||||||
, credsEmail :: Maybe String -- ^ Verified e-mail address.
|
, credsEmail :: Maybe String -- ^ Verified e-mail address.
|
||||||
, credsDisplayName :: Maybe String -- ^ Display name.
|
, credsDisplayName :: Maybe String -- ^ Display name.
|
||||||
, credsId :: Maybe Integer -- ^ Numeric ID, if used.
|
, credsId :: Maybe Integer -- ^ Numeric ID, if used.
|
||||||
|
, credsFacebookToken :: Maybe Facebook.AccessToken
|
||||||
}
|
}
|
||||||
deriving (Show, Read, Eq)
|
deriving (Show, Read, Eq)
|
||||||
|
|
||||||
@ -147,6 +152,9 @@ mkYesodSub "Auth" [("master", [''YesodAuth])] [$parseRoutes|
|
|||||||
/openid/complete OpenIdComplete GET
|
/openid/complete OpenIdComplete GET
|
||||||
/login/rpxnow RpxnowR
|
/login/rpxnow RpxnowR
|
||||||
|
|
||||||
|
/facebook FacebookR GET
|
||||||
|
/facebook/start StartFacebookR GET
|
||||||
|
|
||||||
/register EmailRegisterR GET POST
|
/register EmailRegisterR GET POST
|
||||||
/verify/#EmailId/#String EmailVerifyR GET
|
/verify/#EmailId/#String EmailVerifyR GET
|
||||||
/login EmailLoginR GET POST
|
/login EmailLoginR GET POST
|
||||||
@ -206,7 +214,7 @@ getOpenIdComplete = do
|
|||||||
redirect RedirectTemporary $ toMaster OpenIdR
|
redirect RedirectTemporary $ toMaster OpenIdR
|
||||||
let onSuccess (OpenId.Identifier ident) = do
|
let onSuccess (OpenId.Identifier ident) = do
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
setCreds (Creds ident AuthOpenId Nothing Nothing Nothing) []
|
setCreds (Creds ident AuthOpenId Nothing Nothing Nothing Nothing) []
|
||||||
redirectUltDest RedirectTemporary $ defaultDest y
|
redirectUltDest RedirectTemporary $ defaultDest y
|
||||||
attempt onFailure onSuccess res
|
attempt onFailure onSuccess res
|
||||||
|
|
||||||
@ -229,6 +237,7 @@ handleRpxnowR = do
|
|||||||
(lookup "verifiedEmail" extra)
|
(lookup "verifiedEmail" extra)
|
||||||
(getDisplayName extra)
|
(getDisplayName extra)
|
||||||
Nothing
|
Nothing
|
||||||
|
Nothing
|
||||||
setCreds creds extra
|
setCreds creds extra
|
||||||
either (redirect RedirectTemporary) (redirectString RedirectTemporary) $
|
either (redirect RedirectTemporary) (redirectString RedirectTemporary) $
|
||||||
case pp "dest" of
|
case pp "dest" of
|
||||||
@ -328,7 +337,8 @@ getEmailVerifyR lid key = do
|
|||||||
case (realKey == Just key, memail) of
|
case (realKey == Just key, memail) of
|
||||||
(True, Just email) -> do
|
(True, Just email) -> do
|
||||||
liftIO $ verifyAccount ae lid
|
liftIO $ verifyAccount ae lid
|
||||||
setCreds (Creds email AuthEmail (Just email) Nothing (Just lid)) []
|
setCreds (Creds email AuthEmail (Just email) Nothing (Just lid)
|
||||||
|
Nothing) []
|
||||||
toMaster <- getRouteToMaster
|
toMaster <- getRouteToMaster
|
||||||
redirect RedirectTemporary $ toMaster EmailPasswordR
|
redirect RedirectTemporary $ toMaster EmailPasswordR
|
||||||
_ -> applyLayout "Invalid verification key" mempty [$hamlet|
|
_ -> applyLayout "Invalid verification key" mempty [$hamlet|
|
||||||
@ -376,7 +386,8 @@ postEmailLoginR = do
|
|||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
case mlid of
|
case mlid of
|
||||||
Just lid -> do
|
Just lid -> do
|
||||||
setCreds (Creds email AuthEmail (Just email) Nothing (Just lid)) []
|
setCreds (Creds email AuthEmail (Just email) Nothing (Just lid)
|
||||||
|
Nothing) []
|
||||||
redirectUltDest RedirectTemporary $ defaultDest y
|
redirectUltDest RedirectTemporary $ defaultDest y
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
setMessage $ string "Invalid email/password combination"
|
setMessage $ string "Invalid email/password combination"
|
||||||
@ -389,7 +400,7 @@ getEmailPasswordR = do
|
|||||||
toMaster <- getRouteToMaster
|
toMaster <- getRouteToMaster
|
||||||
mcreds <- maybeCreds
|
mcreds <- maybeCreds
|
||||||
case mcreds of
|
case mcreds of
|
||||||
Just (Creds _ AuthEmail _ _ (Just _)) -> return ()
|
Just (Creds _ AuthEmail _ _ (Just _) _) -> return ()
|
||||||
_ -> do
|
_ -> do
|
||||||
setMessage $ string "You must be logged in to set a password"
|
setMessage $ string "You must be logged in to set a password"
|
||||||
redirect RedirectTemporary $ toMaster EmailLoginR
|
redirect RedirectTemporary $ toMaster EmailLoginR
|
||||||
@ -425,7 +436,7 @@ postEmailPasswordR = do
|
|||||||
redirect RedirectTemporary $ toMaster EmailPasswordR
|
redirect RedirectTemporary $ toMaster EmailPasswordR
|
||||||
mcreds <- maybeCreds
|
mcreds <- maybeCreds
|
||||||
lid <- case mcreds of
|
lid <- case mcreds of
|
||||||
Just (Creds _ AuthEmail _ _ (Just lid)) -> return lid
|
Just (Creds _ AuthEmail _ _ (Just lid) _) -> return lid
|
||||||
_ -> do
|
_ -> do
|
||||||
setMessage $ string "You must be logged in to set a password"
|
setMessage $ string "You must be logged in to set a password"
|
||||||
redirect RedirectTemporary $ toMaster EmailLoginR
|
redirect RedirectTemporary $ toMaster EmailLoginR
|
||||||
@ -481,3 +492,38 @@ inMemoryEmailSettings = do
|
|||||||
spgo eid pass (email, EmailCreds eid' pass' status key)
|
spgo eid pass (email, EmailCreds eid' pass' status key)
|
||||||
| eid == eid' = (email, EmailCreds eid (Just pass) status key)
|
| eid == eid' = (email, EmailCreds eid (Just pass) status key)
|
||||||
| otherwise = (email, EmailCreds eid' pass' status key)
|
| otherwise = (email, EmailCreds eid' pass' status key)
|
||||||
|
|
||||||
|
getFacebookR :: YesodAuth master => GHandler Auth master ()
|
||||||
|
getFacebookR = do
|
||||||
|
y <- getYesod
|
||||||
|
a <- authFacebook <$> getYesodSub
|
||||||
|
case a of
|
||||||
|
Nothing -> notFound
|
||||||
|
Just (cid, secret) -> do
|
||||||
|
render <- getUrlRender
|
||||||
|
tm <- getRouteToMaster
|
||||||
|
let fb = Facebook.Facebook cid secret $ render $ tm FacebookR
|
||||||
|
code <- runFormGet $ required $ input "code"
|
||||||
|
at <- liftIO $ Facebook.getAccessToken fb code
|
||||||
|
so <- liftIO $ Facebook.getGraphData at "me"
|
||||||
|
let c = fromMaybe (error "Invalid response from Facebook") $ do
|
||||||
|
m <- fromMapping so
|
||||||
|
id' <- lookupScalar "id" m
|
||||||
|
let name = lookupScalar "name" m
|
||||||
|
let email = lookupScalar "email" m
|
||||||
|
let id'' = "http://graph.facebook.com/" ++ id'
|
||||||
|
return $ Creds id'' AuthFacebook email name Nothing $ Just at
|
||||||
|
setCreds c []
|
||||||
|
redirectUltDest RedirectTemporary $ defaultDest y
|
||||||
|
|
||||||
|
getStartFacebookR :: GHandler Auth master ()
|
||||||
|
getStartFacebookR = do
|
||||||
|
y <- getYesodSub
|
||||||
|
case authFacebook y of
|
||||||
|
Nothing -> notFound
|
||||||
|
Just (cid, secret) -> do
|
||||||
|
render <- getUrlRender
|
||||||
|
tm <- getRouteToMaster
|
||||||
|
let fb = Facebook.Facebook cid secret $ render $ tm FacebookR
|
||||||
|
let fburl = Facebook.getForwardUrl fb $ authFacebookPerms y
|
||||||
|
redirectString RedirectTemporary fburl
|
||||||
|
|||||||
@ -24,7 +24,7 @@ library
|
|||||||
time >= 1.1.3 && < 1.2,
|
time >= 1.1.3 && < 1.2,
|
||||||
wai >= 0.1.0 && < 0.2,
|
wai >= 0.1.0 && < 0.2,
|
||||||
wai-extra >= 0.1.3 && < 0.2,
|
wai-extra >= 0.1.3 && < 0.2,
|
||||||
authenticate >= 0.6.2 && < 0.7,
|
authenticate >= 0.6.3 && < 0.7,
|
||||||
bytestring >= 0.9.1.4 && < 0.10,
|
bytestring >= 0.9.1.4 && < 0.10,
|
||||||
directory >= 1 && < 1.1,
|
directory >= 1 && < 1.1,
|
||||||
text >= 0.5 && < 0.8,
|
text >= 0.5 && < 0.8,
|
||||||
@ -42,7 +42,8 @@ library
|
|||||||
old-locale >= 1.0.0.2 && < 1.1,
|
old-locale >= 1.0.0.2 && < 1.1,
|
||||||
persistent >= 0.1.0 && < 0.2,
|
persistent >= 0.1.0 && < 0.2,
|
||||||
neither >= 0.0.0 && < 0.1,
|
neither >= 0.0.0 && < 0.1,
|
||||||
MonadCatchIO-transformers >= 0.2.2.0 && < 0.3
|
MonadCatchIO-transformers >= 0.2.2.0 && < 0.3,
|
||||||
|
data-object >= 0.3.1 && < 0.4
|
||||||
exposed-modules: Yesod
|
exposed-modules: Yesod
|
||||||
Yesod.Content
|
Yesod.Content
|
||||||
Yesod.Dispatch
|
Yesod.Dispatch
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user