0

Good day to all web2py experts!

I can't find a way on how to use the web2py Decorators

@auth.requires_permission('read','person')
def f(): ....

in the pdf manual it says that:

prevents visitors from accessing the function f unless the visitor is a member of a group whose members have permissions to "read" records of table "person". If the visitor is not logged in, the visitor gets directed to a login page (provided by default by web2py). web2py also supports components, i.e. actions which can be loaded in a view and interact with the visitor via Ajax without re-loading the entire page. This is done via a LOAD helper which allows very modular design of applications; it is discussed in chapter 3 in the context of the wiki and, in some detail, in the last chapter of this book. This 5th edition of the book describes web2py 2.4.1 and later versions

In my case:

I have list of groups: Admin_Tier_1, Admin_Tier_2, Admin_Tier_3

Admin_Tier_1 - has the highest authority to access all features like adding a school year, set a school year etc.

Admin_Tier_2 - has the authority to add students etc

Admin_Tier_3 - its the lowest level of authority that can only add fines to the students (Organization Officers)

now I use the Decorator code like this:

@auth.requires_permission('Admin_Tier_1','student_list')
def add(): ....

now I login the account of the Chairman which registered in the auth_membership as Admin_Tier_1. Then I click the link "List of Students" which redirect to add(): function but the system returned a message:

Not Authorized
     Insufficient privileges
MeSH
  • 101
  • 1
  • 10
  • i found a temporary solution "@auth.requires(auth.has_membership('Admin_Tier_1'))" but there are two groups can access the add() function these are the Admin_Tier_1 and Admin_Tier_2 groups... so I use this code: "@auth.requires(auth.has_membership(['Admin_Tier_1, Admin_Tier_2']))" but it's not working.... because the system block both the users to accessing the page. – MeSH Oct 13 '15 at 23:52
  • UPDATE 2: I got it work: "@auth.requires([auth.has_membership('Admin_Tier_1'),auth.has_membership('Admin_Tier_2')])" please post an Answer if are more better than the code I provide. I saw another problem.... using the code I provide just now... in the page browser which is "http://127.0.0.1:8000/System/home/add" when logged in as admin then I logged the user where registered as Admin_Tier_3 and try to access this page "http://127.0.0.1:8000/System/home/add" and the user can access it, which is the Admin_Tier_3 has not Authorized to access the add() function. – MeSH Oct 14 '15 at 00:03

2 Answers2

0

Problem solved:

@auth.requires(auth.has_membership('Admin_Tier_1') or auth.has_membership('Admin_Tier_2'))

source here.

Whenever I access the page if the user belong to the group of Admin_Tier_3 the system block the acess and redirect it to "/default/user/not_authorized" page :)

MeSH
  • 101
  • 1
  • 10
0

The auth.requires() method can take a callable rather than a boolean value as the condition, and this is preferable when it is expensive to generate the boolean value (otherwise, the boolean value is generated whenever the controller is accessed, even if the particular decorated function is not the one being called). So, to avoid calling auth.has_membership unnecessarily, you can do:

@auth.requires(lambda: auth.has_membership('Admin_Tier_1') or
                       auth.has_membership('Admin_Tier_2'))

Now the two auth.has_membership calls will only be made when the actual function being decorated is called.

Also, if you need to check a larger number of roles, you can do something like:

@auth.requires(lambda: any([auth.has_membership(r) for r in ['list', 'of', 'roles']))
Anthony
  • 25,466
  • 3
  • 28
  • 57
  • thanks for the reply Anthony.... I think I get the process here "any([auth.has_membership(r) for r in ['list', 'of', 'roles'])" but what about this? "lambda". Based on the web2py pdf 5th edition "lambda" 'provides a way to create a very short unnamed function very easily'. When will the right time to use that "lambda"? I can use that inside the controller function? or only in the @auth? – MeSH Oct 19 '15 at 00:28
  • You can use a lambda anywhere -- it's just a way to create an anonymous function in place rather than having to write a separate function definition. In this case, the alternative would be to define a separate function before specifying the decorator, and then pass that function to the decorator. Of course, as noted, you don't have to use a function at all here -- you can directly pass the boolean condition to the decorator, but in that case, the expression will be evaluated whenever the containing controller is called, even if a different function is being accessed. – Anthony Oct 19 '15 at 14:54