How to use Yesod.Auth.HashDB?

Hello everybody! In one app I develop, users will not register by themselves. Instead, they will be added to the system and assigned roles by administrator. For that case, HashDB auth plugin looked the right choice for me. TL;DR: The setup proposed in Yesod.Auth.HashDB documentation didn't work for me. Finally I found the solution. I wonder if putting User entity definition in Yesod.Auth.HashDB module is a good idea. There are three reasons I post this: to publish my solution for anybody having the same problem, to ask a question if I am doing it right, and, last but not least, to submit a feedback to Yesod authors. In a freshly scaffolded sqlite-based setup made with Yesod-0.10.1, I did changes recommended in Yesod.Auth.HashDB haddock. See these instructions here: http://hackage.haskell.org/packages/archive/yesod-auth/0.8.1/doc/html/Yesod-... Here you can see how I applied these instructions to my project: https://gist.github.com/1793058 . That led to errors shown in the same gist below. These errors do make sense: if User is defined in Yesod.Auth.HashDB, I have to delete the duplicate of definition from my config/models file. But then I get another error: `Model.hs:13:1: Not in scope: type constructor or class `UserGeneric'` Ok, fair enough again. Because now I don't define User entity in config/models, Model.hs must take it from HashDB module. Let's add `import Yesod.Auth.HashDB` to Model.hs file. This fixes the error, but then another one appears: Foundation.hs:158:19: Couldn't match expected type `FCCS -> [AuthPlugin FCCS]' with actual type `[t0]' In the expression: [authHashDB (Just . UniqueUser)] In an equation for `authPlugins': authPlugins = [authHashDB (Just . UniqueUser)] In the instance declaration for `YesodAuth FCCS' Ok, the underscore must be added after definition of authPlugins instance method. Of course, it should be there, even if it's missing in example on top of Yesod.Auth.HashDB haddock. Now, another error: Devel application launched, listening on port 3000 devel.hs: Table not found: User Exit code: ExitFailure 1 Table not found. I checked the database, there is "user" table there. What can this be? Let's swap these lines in Application.hs Now they will be like this: Database.Persist.Store.runPool dbconf (runMigration migrateUsers) p Database.Persist.Store.runPool dbconf (runMigration migrateAll) p Before they were in reverse order. Let's see that happens: Devel application launched, listening on port 3000 Migrating: CREATE TABLE "User"("id" INTEGER PRIMARY KEY,"username" VARCHAR NOT NULL,"password" VARCHAR NOT NULL,"salt" VARCHAR NOT NULL,CONSTRAINT "UniqueUser" UNIQUE ("username")) devel.hs: user error (SQLite3 returned ErrorError while attempting to perform prepare "CREATE TABLE \"User\"(\"id\" INTEGER PRIMARY KEY,\"username\" VARCHAR NOT NULL,\"password\" VARCHAR NOT NULL,\"salt\" VARCHAR NOT NULL,CONSTRAINT \"UniqueUser\" UNIQUE (\"username\"))": table "User" already exists) Exit code: ExitFailure 1 Other error, but no luck yet. What if we drop the table "User"? Migrating: CREATE TABLE "User"("id" INTEGER PRIMARY KEY,"username" VARCHAR NOT NULL,"password" VARCHAR NOT NULL,"salt" VARCHAR NOT NULL,CONSTRAINT "UniqueUser" UNIQUE ("username")) devel.hs: Table not found: User Exit code: ExitFailure 1 What if we delete the database altogether? `devel.hs: Table not found: User` Of course it is not found. But what can I do to fix this? Surely I don't know what I am doing here. Any clarifications? And then it occurred to me that even if I managed to get it working that way, this still will be not quite right. What if I will decide to add some fields to User entity later? I can't do it if User is exported from HashDB. And I really plan to add one field just after I make this work. The "role" field to manage permissions. So, instead, I copied the definition from HashDB source to my config/models: User username Text Eq password Text salt Text UniqueUser username And then copied the instance definition to Model.hs: instance HashDBUser (UserGeneric backend) where userPasswordHash = Just . userPassword userPasswordSalt = Just . userSalt setSaltAndPasswordHash s h u = u { userSalt = s , userPassword = h } To eliminate conflicts, in Model.hs the import was restricted to `import Yesod.Auth.HashDB (HashDBUser(..))` In Application.hs it was removed along with migration command, and Foundation.hs it was narrowed to `import Yesod.Auth.HashDB (authHashDB, getAuthIdHashDB)` Finally, it worked. You may want to look at https://gist.github.com/1793594 for the set of changes needed to achieve this. Anyway, I can't get rid of the feeling that there is some "right" method to do this, that I either overlooked, or couldn't come up with myself. Any advice?
participants (1)
-
Michael Lazarev