Access control example¶
As explained previously, objects are annotated to state which Fields or Events they expose to a user interface. Fields and Events supply extra information that is useful to user interfaces. Fields are not only used for validation – amongst other things they are also used to declare who is allowed to see or change the data items they represent. This information is used to automatically adapt what is rendered on the screen to prevent editing or visibility when necessary.
Similar access control features are present for Events controlling the visibility or state of rendered Buttons.
The example program presented here renders a single page with an input and a button. Each of these elements are restricted in some way:
- The input labelled Greyed out is for a Field that is allowed to be read but not written (ie, changed).
- The Greyed out button is greyed out for similar reasons: the user may see the button, but is not allowed to execute its action.
(Of course, Inputs that are not allowed to be read or written will simply not be rendered at all.)
Here is the example source code, followed by some explanation:
from __future__ import print_function, unicode_literals, absolute_import, division from reahl.web.fw import UserInterface from reahl.web.ui import HTML5Page, Form, TextInput, Button, LabelledBlockInput from reahl.component.modelinterface import secured, Action, Event from reahl.component.modelinterface import exposed, EmailField class AccessUI(UserInterface): def assemble(self): self.define_view('/', title='Access control demo', page=HomePage.factory()) class HomePage(HTML5Page): def __init__(self, view): super(HomePage, self).__init__(view, style='basic') self.body.add_child(CommentForm(view)) class Comment(object): def always_allowed(self): return True def never_allowed(self): return False @exposed def fields(self, fields): fields.greyed_out_field = EmailField(label='Greyed out', default='some default value', readable=Action(self.always_allowed), writable=Action(self.never_allowed)) @exposed def events(self, events): events.greyed_out_event = Event(label='Greyed out button', action=Action(self.do_something)) @secured(read_check=always_allowed, write_check=never_allowed) def do_something(self): pass class CommentForm(Form): def __init__(self, view): super(CommentForm, self).__init__(view, 'myform') comment = Comment() text_input = TextInput(self, comment.fields.greyed_out_field) self.add_child(LabelledBlockInput(text_input)) self.define_event_handler(comment.events.greyed_out_event) self.add_child( Button(self, comment.events.greyed_out_event) )
Notice how one specifies an Action for the framework to call in order to determine whether a Field is readable or writable. These Actions should return True or False to indicate whether the user has the corresponding right or not, respectively (obviously you won’t hard-code them like in this example...).
Methods can be marked as @secured. A secured method is adorned with similar checks which are called to establish whether the secured method is allowed to be read (Buttons will be visible) or written (Buttons will be enabled) respectively. (These check methods return True if the right is allowed, else False.)
An Event can infer its access rights directly from the access rights applicable to the method used as its action.
If a programmer somehow mistakenly does call such a secured method when it is not allowed, an exception will be raised.