From e3e3d6377a73c72f8c9e04ec6c5a5151cfd005ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Fri, 3 Mar 2017 10:54:10 +0100 Subject: [PATCH] Improve auth-setup instructions --- ...ntication-authorization-and-permissions.md | 155 +++++++++++------- 1 file changed, 99 insertions(+), 56 deletions(-) diff --git a/pages/en/lb3/Authentication-authorization-and-permissions.md b/pages/en/lb3/Authentication-authorization-and-permissions.md index 3b3f5df9f..8115cb1a6 100644 --- a/pages/en/lb3/Authentication-authorization-and-permissions.md +++ b/pages/en/lb3/Authentication-authorization-and-permissions.md @@ -68,55 +68,88 @@ module.exports = function enableAuthentication(server) { ### Preparing access control models -Make sure the `User` model, (and possibly the `AccessToken` model) is configured appropriately according to your set-up. +You must configure the `User` model(s), (and possibly the `AccessToken` model) according to your set-up. -Normally you should have already implemented at least one custom user model, extending the built-in `User` model, as described in [Using built-in models](Using-built-in-models.html#user-model). +The best practice is to implement at least one custom user model extending the built-in `User` model instead of using the built-in `User` model as-is, as described in [Using built-in models](Using-built-in-models.html#user-model). -Usually you don't need to extend or customize the built-in models `Role`, `RoleMapping`, and `ACL`. Just make sure they are declared in the `model-config.json` configuration file, or in case you don't require either to customize the `AccessToken` model that you pass a datasource to the `enableAuth()` method as follows: +Usually you don't need to extend or customize the built-in models `Role`, `RoleMapping`, and `ACL`. Just make sure they are declared in the `model-config.json` configuration file, or if you don't need to customize the `AccessToken` model, pass a datasource to the `enableAuth()` method as follows: ```javascript server.enableAuth({ datasource: 'db' }); ``` -{% include note.html content=" -Passing a `datasource` to the `enableAuth()` method as shown here will let LoopBack take care of attaching any built-in models required by the access control feature, which is suitable for most applications. +{% include note.html content="Passing a `datasource` to the `enableAuth()` method as shown here will let LoopBack take care of attaching any built-in models required by the access control feature, which is suitable for most applications. " %} -{% include tip.html content=" -Whether you can use the built-in `AccessToken` model or create a custom accessToken model extending the built-in model depends on whether you plan to use one or several user models extending the built-in `User` model. Both cases are covered in the next two sections. +{% include tip.html content="Whether you can use the built-in `AccessToken` model or create a custom model that extends `AccessToken` depends on whether you plan to use one or several user models extending the built-in `User` model, as described in the following sections. " %} #### Access control with a single user model -If your application leverages only one type of user extending the built-in `User` model (which should the case in a majority of configurations), you have little further configuration to do. +In the most common scenario, an application uses only one model that extends the built-in `User` model +and uses the built-in `AccessToken` model. In this case, you need to change the "belongsTo" relation of the built-in `AccessToken` model to refer to your custom User model. To do this, edit `server/model-config.json` file as follows: -1. Rely on the built-in `AccessToken` model. -2. Make sure your custom user model implements a hasMany relation with the AccessToken model as follows: +{% include code-caption.html content="server/model-config.json" %} +```json +{ + // ... + "AccessToken": { + "dataSource": "db", + "public": false, + "relations": { + "user": { + "type": "belongsTo", + "model": "user", + "foreignKey": "userId" + } + } + } + // ... +} +``` + +{% include tip.html content="Model relations are preserved when extending models, therefore your custom `User` model will automatically have a hasMany relation to the default `AccessToken` model. +" %} + +##### Customizing the AccessToken model + +If your application needs to customize the `AccessToken` model, for example +to add extra properties, then you need to modify the `User` model to use +the new `AccessToken` model for authentication. + +In your custom `User` model definition file, make sure the `relations` section +configures the "accessTokens" relation to use your custom `AccessToken` model +as shown here: {% include code-caption.html content="common/models/custom-user.json" %} ```json -... -"relations": { - "accessTokens": { - "type": "hasMany", - "model": "AccessToken", - "foreignKey": "userId", - "options": { - "disableInclude": true - } - } -}, -... +{ + "name": "CustomUser", + "base": "User", + // ... + "relations": { + "accessTokens": { + "type": "hasMany", + "model": "AccessToken", + "foreignKey": "userId", + "options": { + "disableInclude": true + } + } + }, + // ... +} ``` #### Access control with multiple user models -Having multiple user models may be required in certain situations to deal with significantly different types of users in an application. +An application with significantly different types of users may require multiple user models. If the types of users differ by just a few properties, then it's easiest to overload a single custom user model with all properties required, and differentiate access control behavior with static roles mapped to the different user types. -A more complex situation is when the different types of users differ not just in their properties, but also by their access rights and relations with other models. For example, applications where the concept of an _organization_ is involved, creating intertwined layers of relationships and thus of access control. -Such circumstances require the application to manage the different user types in separate models. +If however the different types of users have different access rights and relations with other models +or if their properties differ too much from each other, +then you may need to use multiple distinct user models. For example, applications where the concept of an _organization_ is involved, creating intertwined layers of relationships and thus of access control. Consider the following example: @@ -135,57 +168,65 @@ Each type of user has different relations with and access rights to the models c ##### Setup -{% include important.html content=" -When using multiple user models, you should not let LoopBack auto-attach built-in models required by the access control feature. Instead, call the `enableAuth()` method with no argument and manually define all models required in the `server/model-config.json` configuration file. +{% include important.html content="When using multiple user models, you should not let LoopBack auto-attach built-in models required by the access control feature. Instead, call the `enableAuth()` method with no argument and manually define all models required in the `server/model-config.json` configuration file. " %} To use several models extending the built-in `User` model, you must modify the relations between the `users` models and the `AccessToken` models to allow a single `AccessToken` model to host access tokens for multiple types of users while at the same time allowing each `user` model instance to be linked to unique related access tokens. -This is achieved by changing the **hasMany** relation from `User` to `AccessToken` and the **belongsTo** relation from `AccessToken` to `User` by their [polymorphic](Polymorphic-relations.html) equivalents, in which the `principalType` property is used as a _discriminator_ to resolve which of the potential `user` model instance an 'accessToken' instance belongs to. +This is achieved by changing the **hasMany** relation from `User` to `AccessToken` and the **belongsTo** relation from `AccessToken` to `User` by their [polymorphic](Polymorphic-relations.html) equivalents, in which the `principalType` property is used as a _discriminator_ to resolve which of the potential `user` model instance an 'accessToken' instance belongs to. In addition to having custom user models this requires you also define a **custom AccessToken** model extending the built-in `AccessToken` model. {% include note.html content="Adapt the following configuration snippets in your custom `users` and `accessToken` model definitions. "%} {% include code-caption.html content="common/models/any-custom-user.json" %} ```json -... -"relations": { - "accessTokens": { - "type": "hasMany", - "model": "customAccessToken", - "polymorphic": { - "foreignKey": "userId", - "discriminator": "principalType" - }, - "options": { - "disableInclude": true +{ + "name": "AnyCustomUser", + "base": "User", + // .. + "relations": { + "accessTokens": { + "type": "hasMany", + "model": "CustomAccessToken", + "polymorphic": { + "foreignKey": "userId", + "discriminator": "principalType" + }, + "options": { + "disableInclude": true + } } - } -}, + }, + // .. +} ... ``` {% include code-caption.html content="common/models/custom-access-token.json" %} ```json -... -"relations": { - "user": { - "type": "belongsTo", - "idName": "id", - "polymorphic": { - "idType": "string", - "foreignKey": "userId", - "discriminator": "principalType" +{ + "name": "CustomAccessToken", + "base": "AccessToken", + // .. + "relations": { + "user": { + "type": "belongsTo", + "idName": "id", + "polymorphic": { + "idType": "string", + "foreignKey": "userId", + "discriminator": "principalType" + } } - } -}, -... + }, + // ... +} ``` {% include important.html content=" In particular, pay attention to: -* The `model` name used to refer to the access token model in the different user models (here named \"customAccessToken\") +* The `model` name used to refer to the access token model in the different user models (here named \"CustomAccessToken\") * The `idName` used for the foreignKey in the access token model referring to the user instance (here named \"id\") * The `idType` used for this foreignKey, according to the type of connector used for the related user models (here using \"string\" for a MongoDB connector for example) * Use \"principalType\" for the `discriminator` name. This is mandatory and cannot be changed @@ -196,13 +237,15 @@ Don't forget to specify the custom `accessToken` model as follows: {% include code-caption.html content="server/middleware.json" %} ```json { + // ... "auth": { "loopback#token": { "params": { - "model": "customAccessToken" + "model": "CustomAccessToken" } } } + // ... } ``` @@ -213,7 +256,7 @@ Don't forget to specify the custom `accessToken` model as follows: var loopback = require('loopback'); ... app.use(loopback.token({ - model: app.models.customAccessToken + model: app.models.CustomAccessToken })); ```