Problem
We wanted to implement Loopback.io as an API for our mobile app development, but needed it to play nice with our Yii2 web environment. We needed to be able to authenticate our Loopback / API users on the same user table that we authenticate our website users, using the same encrypted password.
Solution
This ended up being easier than I thought. Here are the steps that I followed:
- Create an AppUser class that inherits from User.
- Override the table that the AppUser class uses as its datastore.
- Create some Loopback fields in my user table.
- Tell AppUser to use the pre-existing primary key
- Turn off email validation
1. Create an AppUser Class to inherit from User
I took my cues from the
documentation on how to make a class that extends User. Download the example referenced in the documentation to get the files. However, I called my class "AppUser" instead of "user", changing user.js and user.json to app-user.js and app-user.json.
I list my AppUser.json below. I left the AppUser.js as it was provided.
2. Override the table the ash AppUser class uses as its datastore.
By default, Loopback will try to use a table called AppUser to match the name of the class. In my example, I need it to reference the
user table in the database, which my Yii2 application already uses. I used the
documentation on this page. to figure out how to do this.
In the AppUser.json file, add the following section:
"options": {
"mysql": {
"table": "user"
}
},
Where user is the name of my table that I want the AppUser class to use as its datastore, instead of the default "AppUser" table.
3. Create some Loopback fields in my user table.
ALTER TABLE `user` ADD `realm` varchar(512);
ALTER TABLE `user` ADD `emailVerified` tinyint(1);
ALTER TABLE `user` ADD `verificationToken` varchar(512);
4. Tell AppUser to use the pre-existing primary key
I already had my own user_id column setup as the primary key. Loopback will try to use a column called id as the primary key by default. To prevent that, I set the field in the properties section with "id": "true" so that AppUser knows to use user_id as the primary key.
"properties": {
"user_id": {
"type": "number",
"id": true
},
"account_id": {
"type": "number",
"required": "true"
}
}
(I setup the account_id field as my Loopback app will need to reference that column. You would setup your other column/fields under properties)
I also set the idInjection section to false, so Loopback won't try and use the "id" field.
5. Turn off email validation.
Insert the following in the AppUser.js file. "emailVerificationRequired": false,
Here is my entire AppUser.json file:
{
"name": "AppUser",
"base": "User",
"idInjection": false,
"restrictResetPasswordTokenScope": true,
"emailVerificationRequired": false,
"validations": [],
"relations": {},
"acls": [
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "login"
},
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "logout"
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "findById"
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "updateAttributes"
}
],
"methods": {},
"options": {
"mysql": {
"table": "user"
}
},
"properties": {
"user_id": {
"type": "number",
"id": true
},
"account_id": {
"type": "number",
"required": "true"
}
}
}