[Grok-dev] Putting together the authentication plugin and a Session. Is that possible?
Sebastian Ware
sebastian at urbantalk.se
Tue Jan 4 11:19:19 EST 2011
If you intend to store large amounts of users in your cache you might want to use a grok.Container or a simple Btree. Every time you access the dict Zodb will fetch all items when accessing a dict, but only selected ones with a Btree based alternative.
Not sure where the tipping point is for this, but it could be worth considering.
Mvh Sebastian
4 jan 2011 kl. 00.45 skrev Hector Blanco:
> Hello list...
>
> I have "fixed" it putting a very simple "cache" (...erm... ok, ok... a
> dict() with the shape <userName, User()>, but "cache" sounds better )
> in the "UserManager" class so if the user is not in the cache, queries
> the database, but if it is in the dict, return the value from the
> dict.
>
> It seems to work...
>
> 2010/12/28 Hector Blanco <white.lists at gmail.com>:
>> Oh, I see... Actually, that's how I have it done (good to see I wasn't
>> totally wrong)
>>
>> class MySessionCredentialsPlugin(grok.GlobalUtility, SessionCredentialsPlugin):
>> grok.provides(ICredentialsPlugin)
>> grok.name('credentials')
>>
>> loginpagename = 'login'
>> loginfield = 'form.login'
>> passwordfield = 'form.hashedPwd'
>>
>> ... and ...
>>
>> class MyOwnPrincipalInfo(object):
>> grok.implements(IPrincipalInfo)
>>
>> The issue is that the getAccount() method seems to be called a lot of times
>>
>> class UserAuthenticatorPlugin(grok.GlobalUtility):
>> grok.provides(IAuthenticatorPlugin)
>> grok.name('users')
>> grok.context(Server)
>>
>> def getAccount(self, login):
>> try:
>> return grok.getSite()["UserManager"].getByName(login, allData=False)
>> except Exception, e:
>> log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>> finally:
>> Database.session.close()
>>
>> def authenticateCredentials(self, credentials):
>> if isinstance(credentials, dict):
>> if (("login" in credentials) and ("password" in credentials)):
>> user = self.getAccount(credentials['login'])
>> if user and (user.checkPassword(credentials['password'])):
>> log.debug("::UserAuthenticatorPlugin > authenticateCredentials >
>> Credentials authenticated for user %s " % (user.userName))
>> return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
>> return None
>>
>> And I don't know how to avoid that...
>>
>> For other views, I understand I can use the [self].request.principal.
>> For instance:
>>
>> class OtherPage(grok.View):
>> grok.context(Server)
>> grok.require('server.ViewSite')
>>
>> def update(self):
>> if self.request.principal.id == "peter":
>> # do stuff
>>
>> , but I don't see how to access that information in the "getAccount"
>> method (or in authenticateCredentials, which seems to be the method
>> calling getAccount). In the "authenticateCredentials" itself, it'd be
>> nice to check if the user has already been authenticated and then
>> return the request.principal, instead of having to call getAccount()
>> (access the database) and then instantiate a new MyOwnPrincipalInfo()
>> object (which, if I understood properly, is in the request already
>> once that the user has been authenticated once)
>>
>> Thanks!
>>
>> 2010/12/28 Jeffrey Peterson <bgpete at gmail.com>:
>>> So you followed that tutorial. In there it includes session based login. it's outdated a bit but if you change a few imports still valid.
>>>
>>> Your Credentials utility needs to inherit from SessionCredentialsPlugin: from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
>>>
>>> MyOwnPrincipalInfo needs to implement IPrincipalInfo, and then the principal will be in the request: self.request.principal it doesn't AFAIK access the DB multiple times. The principal is in the request until logout, or session expiration.
>>>
>>> Jeff.
>>> On Dec 27, 2010, at 6:14 PM, Hector Blanco wrote:
>>>
>>>> Hello list:
>>>>
>>>> I have set up a user authentication mechanism as explained in
>>>> http://grok.zope.org/documentation/how-to/authentication-with-grok
>>>>
>>>> The users structure is serialized on a MySQL database.
>>>>
>>>> I have setup the "authenticateCredentials" and "getAccount" methods
>>>> for the authenticator plugin like this
>>>>
>>>> def authenticateCredentials(self, credentials):
>>>> if isinstance(credentials, dict):
>>>> if (("login" in credentials) and ("password" in credentials)):
>>>> user = self.getAccount(credentials['login'])
>>>> if user and (user.checkPassword(credentials['password'])):
>>>> log.debug("::UserAuthenticatorPlugin > authenticateCredentials >
>>>> Credentials authenticated for user %s " % (user.userName))
>>>> return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
>>>> return None
>>>>
>>>> def getAccount(self, login):
>>>> try:
>>>> return grok.getSite()["UserManager"].getByName(login, allData=False)
>>>> except Exception, e:
>>>> log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>>>> log.debug("::UserAuthenticatorPlugin > getAccount > Showing
>>>> traceback:\n%s" % traceback.format_exc(limit=5))
>>>> finally:
>>>> Database.session.close()
>>>>
>>>> The "UserManager" is just a bunch of static methods that access the
>>>> database (using SqlAlchemy) and, in this case, tries to get the user
>>>> whose "userName" is the same in "login". That means having to access
>>>> the database many, many times.
>>>>
>>>> So here's the question:
>>>> Is there any way of using the ISession object so I don't have to query
>>>> the database so often?
>>>>
>>>> The idea would be putting "something" in the "authenticateCredentials"
>>>> method so if userName and password are correct, a new entry for that
>>>> user is created in the session object, so I can get it from there,
>>>> instead of having to access the database that often.
>>>>
>>>> Something that would allow me to modify the getAccount() method to
>>>> something like this:
>>>>
>>>> def getAccount(self, login):
>>>> try:
>>>> if (ISession(self.request)['users'][self.request.principal.id]):
>>>> return =
>>>> ISession(self.request)['users'][self.request.principal.id]
>>>> else:
>>>> return
>>>> grok.getSite()["UserManager"].getByName(login, allData=False)
>>>> except Exception, e:
>>>> log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>>>> log.debug("::UserAuthenticatorPlugin > getAccount > Showing
>>>> traceback:\n%s" % traceback.format_exc(limit=5))
>>>> finally:
>>>> Database.session.close()
>>>>
>>>> But that's the issue... in order to use the session, I need to have
>>>> access to a .request, right? And in getAccount(self...), self is an
>>>> instance of "UserAuthenticatorPlugin", which doesn't have any request
>>>> associated (at least, not that I have seen)
>>>>
>>>> Is there any way to access the request from an instance of
>>>> "UserAuthenticatorPlugin"? The idea would be "registering" the user
>>>> that is authenticated in the Session object so I don't have to access
>>>> the database that many times...
>>>>
>>>> Thank you in advance!
>>>> _______________________________________________
>>>> Grok-dev mailing list
>>>> Grok-dev at zope.org
>>>> https://mail.zope.org/mailman/listinfo/grok-dev
>>>
>>>
>>
> _______________________________________________
> Grok-dev mailing list
> Grok-dev at zope.org
> https://mail.zope.org/mailman/listinfo/grok-dev
More information about the Grok-dev
mailing list