Flask 101: How to Add a Search Form. Join the DZone community and get the full member experience. We added a database to our Flask web application but didn’t have a way to add anything to.
username and password style that is queried from the database to match. Passwords are kept hashed on the database.
Uses the user’s email field to authenticate on Gmail, Yahoo etc…
Authentication against an LDAP server, like Microsoft Active Directory.
Reads the REMOTE_USER web server environ var, and verifies if it’s authorized with the framework users table.It’s the web server responsibility to authenticate the user, useful for intranet sites, when the server (Apache, Nginx)is configured to use kerberos, no need for the user to login with username and password on F.A.B.
Authentication using OAUTH (v1 or v2). Gsm key generation and encryption processor. You need to install flask-oauthlib.
Configure the authentication type on config.py, take a look at Base Configuration
The session is preserved and encrypted using Flask-Login, OpenID requires Flask-OpenID.
Each user may have multiple roles, and a role holds permissions on views/API and menus,so a user has permissions on views/API and menus.
Roles can be user defined (backed by the backend) and builtin readonly. Builtin readonly rolessupport regex for views/API and permissions, this simplifies security management andimprove performance since the many to many permissions between a role and it’s permissionsdoes not need to be fetched from the backend.
Builtin roles are defined on the config using FAB_ROLES
key and respect the following data structure:
So for example a Read Only role might look like:
These roles are inserted automatically to the database (only their name is added), andcan be associated to users just like a “normal”/user defined role.
If you want to later on change the name of these roles, you can map these roles by their backend id:
There are two special roles, you can define their names on the Base Configuration
Special builtin read only Role, will have full access.
This is a special role for non authenticated users,you can assign all the permissions on views and menus to this role,and everyone will access specific parts of you application.
Of course you can create any additional role you want and configure them as you like.
The framework automatically creates for you all the possible existing permissions on your views, API or menus,by “inspecting” your code.
Each time you create a new view based on a model (inherit from ModelView) it will create the following permissions:
can list
can show
can add
can edit
can delete
can download
In the case of CRUD REST API:
can get
can put
can post
can delete
can info
These base permissions will be associated to your view or API, so if you create a view named MyModelView
you can assign to any role the following permissions:
can list on MyModelView
can show on MyModelView
can add on MyModelView
can edit on MyModelView
can delete on MyModelView
can download on MyModelView
In case your developing a backend REST API subclassing ModelRestApi
with a class named MyApi
willgenerate the following permissions:
can get on MyApi
can put on MyApi
can post on MyApi
can delete on MyApi
can info on MyApi
If you extend your view with some exposed method via the @expose
decorator and you want to protect ituse the @has_access
decorator:
The framework will create the following access, based on your method’s name:
can mymethod on MyModelView
You can aggregate some of your method’s on a single permission, this can simplify the security configurationif there is no need for granular permissions on a group of methods, for this use @permission_name
decorator.
You can use the @permission_name
to override the permission’s name to whatever you like.
Take a look at API Reference
The default view/menu, permissions are highly granular, this is a good default since it enables a high levelof customization, but on medium to large application the amount of permission pairs generated can get a bit daunting.You can fully customize the generated permission names generated and if you wish aggregate them:
The previous example will generate half the default permissions, by just creating the following:
can get on api
can put on api
can post on api
can delete on api
can info on api
The class_permission_name
property is available also on BaseViews and their children ModelView
,MultipleView
, MasterDetailView
, FormView
, etc.
You can also aggregate method permissions by using method_permission_name
attribute.Use the following Dict
structure:
Example:
Now FAB will only generate one permission pair:
can access on api
If you want to revert back your permission names override, or change just them again, you need to hint FABabout what were your last permissions, so that the security converge procedure knows what to do:
An example for compressing permissions using MVC Model Views:
Note that if your changing an already existing application, you need to migrate the old permission names to the newones. Before doing that you should disable the boot automatic create/delete permissions,so set FAB_UPDATE_PERMS=False
. Then run the following FAB cli command:
Security converge will migrate all your permissions from the previous names to the current names, andalso change all your roles, so you can migrate smoothly to your new security naming. After convergingyou can delete all your previous_*
attributes if you have set them.
You can also migrate back by switching previous_*
attributes to their target, ie switchprevious_method_permission_name
by method_permission_name
andprevious_class_permission_name
by class_permission_name
.Then run security converge will expand back all permissionson all your Roles.
You should backup your production database before migrating your permissions. Also note that youcan run flaskfabsecurity-converge--dry-run
to get a list of operations the converge will perform.
All your permissions and views are added automatically to the backend and associated with the ‘Admin’ role.The same applies to removing them. But, if you change the name of a view or menu, the frameworkwill add the new Views and Menus names to the backend, but will not delete the old ones. It will generate unwantednames on the security models, basically garbage. To clean them, use the security_cleanup method.
Using security_cleanup is not always necessary, but using it after code rework, will guarantee that the permissions, andassociated permissions to menus and views are exactly what exists on your app. It will prevent orphaned permission namesand associations.
Use the cleanup after you have registered all your views.
You can always use it and everything will be painlessly automatic. But if you use it only when needed(change class name, add security_cleanup to your code, the garbage names are removed, then remove the method)no overhead is added when starting your site.
All user’s creation and modification are audited.On the show detail for each user you can check who created the user and when and who has last changed it.
You can check also, a total login count (successful login), and the last failed logins(these are reset if a successful login occurred).
If you’re using SQLAlchemy you can mix auditing to your models in a simple way. Mix AuditMixin class to your models:
This will add the following columns to your model:
created_on: The date and time of the record creation.
changed_on: The last date and time of record update.
created_by: Who created the record.
changed_by: Who last modified the record.
These columns will be automatically updated by the framework upon creation or update of records. So you shouldexclude them from add and edit form. Using our example you will define our view like this:
We are now looking at the authentication methods, and how you can configure them and customize them.The framework has 5 authentication methods and you choose one of them, you configure the method to be usedon the config.py (when using the create-app, or following the proposed app structure). First theconfiguration imports the constants for the authentication methods:
Next you will use the AUTH_TYPE key to choose the type:
Additionally you can customize the name of the builtin roles for Admin and Public accesses:
Finally you can allow users to self register (take a look at the following chapters for further detail):
These settings can apply to all the authentication methods. When you create your first admin userusing flask fab command line, this user will be authenticated using the authentication methoddefined on your config.py.
The database authentication type is the most simple one, it authenticates users against anusername and hashed password field kept on your database.
Administrators can create users with passwords, and users can change their passwords. This is all done using the UI.(You can override and extend the default UI as we’ll see on Your Custom Security)
This authentication method uses Flask-OpenID. All configuration is doneon config.py using OPENID_PROVIDERS key, just add or remove from the list the providers you want to enable:
Each list entry is a dict with a readable OpenID name and it’s url, if the url needs an username just add it using <username>.The login template for this method will provide a text box for the user to fillout his/her username.
F.A.B. will ask for the ‘email’ from OpenID, and if this email belongs to some user on your application he/she will login successfully.
This method will authenticate the user’s credentials against an LDAP server. Using this method without self user registrationis very simple, for MSFT AD just define the LDAP server:
For OpenLDAP or if you need/want to bind first with a query LDAP user,then using username to search the LDAP server and binding to it (using the user provided password):
for MSFT AD users will be authenticated using the attribute ‘userPrincipalName’, so username’s will be of the form‘someuser@somedomail.local’. Since 1.6.1 you can use a new configuration to set all domains to a certain default,this will allow users to authenticate using ‘someuser’ be setting:
When using self user registration, you can use the following to config further:
Default to ‘uid’ will be used to search the user on the LDAP server.For MSFT AD you can set it to ‘userPrincipalName’
Default to ‘givenName’ will use MSFT AD attribute to register first_name on the db.
Default to ‘sn’ will use MSFT AD attribute to register last_name on the db.
Default to ‘mail’ will use MSFT AD attribute to register email on the db.If this attribute is null the framework will register <username + ‘@email.notfound’>
This must be set when using self user registration.
By using this method it will be possible to use the provider API, this is because you’re requesting the user to givepermission to your app to access or manage the user’s account on the provider.
So you can send tweets, post on the users facebook, retrieve the user’s linkedin profile etc.
To use OAuth you need to install Flask-OAuthLib. It’s usefulto get to know this library since F.A.B. will expose the remote application object for you to play with.
Take a look at the exampleto get an idea of a simple use for this.
Use config.py configure OAUTH_PROVIDERS with a list of oauth providers, notice that the remote_appkey is just the configuration for flask-oauthlib:
This needs a small explanation, you basically have five special keys:
The name of the provider, you can choose whatever you want. But the framework as somebuiltin logic to retrieve information about a user that you can make use of if you choose:‘twitter’, ‘google’, ‘github’,’linkedin’.
The font-awesome icon for this provider.
The token key name that this provider uses, google and github uses ‘access_token’,twitter uses ‘oauth_token’ and thats the default.
The token secret key name, default is ‘oauth_token_secret’
After the user authenticates and grants access permissions to your applicationthe framework retrieves information about the user, username and email. This infowill be checked with the internal user (user record on User Model), first by username next by email.
To override/customize the user information retrieval from oauth, you can create your own method like this:
Decorate your method with the SecurityManager oauth_user_info_getter decorator.Make your method accept the exact parameters as on this example, and then return a dictionarywith the retrieved user information. The dictionary keys must have the same column names as the User Model.Your method will be called after the user authorizes your application on the OAuth provider, and it willreceive the following: sm is F.A.B’s SecurityManager class, provider is a string with the name you configuredthis provider with, response is the response.
Take a look at the example
If you want to alter the security views, or authentication methods since (1.0.1) you can do it in a simple way.The AppBuilder has a new optional initialization parameter where you pass your own custom SecurityManagerIf you want to add, for example, actions to the list of users you can do it in a simple way.
First i advise you to create security.py and add the following to it:
Then on the __init__.py initialize AppBuilder with you own security class:
Alternatively since 1.13.1 you can declare your custom SecurityManager on the config.This is a must have if your using the factory app pattern, on the config declare you class the following way:
F.A.B. uses a different user view for each authentication method
For database auth method
For Open ID auth method
For LDAP auth method
You can extend or create from scratch your own, and then tell F.A.B. to use them instead, by overriding theircorrespondent lower case properties on SecurityManager (just like on the given example).
Take a look and run the example on Employees example
Study the source code of BaseSecurityManager
If you want to extend the User Model with extra columns specific to your application (since 1.3.0) youcan easily do it. Use the same type of approach as explained earlier.
First extend the User Model (create a sec_models.py file):
Next define a new User view, just like the default User view but with the extra column (create a sec_view.py)If you’re using:
Extend UserDBModelView
Extend UserLDAPModelView
Extend UserRemoteUserModelView
Extend UserOIDModelView
Extend UserOAuthModelView
So using AUTH_DB:
Next create your own SecurityManager class, overriding your model and view for User (create a sec.py):
Note that this is for AUTH_DB, so if you’re using:
Override userdbmodelview
Override userldapmodelview
Override userremoteusermodelview
Override useroidmodelview
Finally (as shown on the previous example) tell F.A.B. to use your SecurityManager class, so when initializingAppBuilder (on __init__.py):
Now you’ll have your extended User model as the authenticated user, g.user will have your model with the extra col.
Some images: