I'm trying to find a way to modify a web page based on the a user's authorization. For example, the owner of a resource should see edit and delete buttons while a regular user should not see those.
The following is a method I am thinking about, but am unsure if there is a more common/better way.
For example, assume there is a resource
project: {
name: string,
owner_id: id,
moderators: [ids],
other_stuff: string
}
Would it be RESTful and good practice to extend this object with an attribute that describes what role the current logged in user is? For example, assuming this user is one of the moderators, it'd send
project: {
name: string,
owner_id: id,
moderators: [ids],
other_stuff: string,
user_role: "moderator"
}
Then the client-side framework would use project.user_role to display role-based controls such as delete and edit.
Related
I'm just getting started with Strapi.io and I'm currently working on a dummy project to test it out. Note that since I'm using the UI, I don't have any code to share, but I'll try to be as explicit as I can to describe what I want and what I've tried.
I have created a "todo" collection type that has a title, description, category and a user associated with it. The user is a relationship (one user has many todos) to the default user entity created with the Strapi app. When I run http POST http://localhost:1337/todos "Authorization: Bearer <TOKEN>" title="title" description="description" category="category" (I'm doing it with Postman) it works, but I see that the user field is null. I would like it to be automatically assigned based on the user who posted this command. Is that possible to achieve?
Many thanks!
Yes, it's absolutely possible. The way you do this is, you first identify which user actually made this request. This can be done by accessing the ctx.state.user variable. This is a global variable set by Koa so you can access this in the controller. Now to save the relationship of user against the todo collection entry you only need to pass the user id of the user calling this api. This can be retrieved by using ctx.state.user.id. So you can use the code below to create a todo collection correctly:
Sample code:
await strapi.services.todo.create({
title: 'My Todo Title',
description: 'My Description here',
category: 'Work',
user: ctx.state.user.id
})
P.S: You need to make sure you're logged in and are using a bearer token while calling the api or else, ctx.state.user will be null.
We have a monolith application and looking to decouple the authentication / authorization service.
At this stage, authorization is the simplest to start with.
The problem comes with authorizing certain type of access to resources. e.g. a user can edit only his own posts.
Given that the microservice will hold only roles/auth items and assignments to an user id, does it make sense to create the following endpoint?
POST v1/<userEmail>/authorize/<authItemName>
with data, e.g.
v1/user#company.com/authorize/Posts.UpdateOwn`
{
post: {
content: 'My first post'
...
creator: {
email: user#company.com
}
}
}
Where we would send the object's data and the user's data. That way I can have a rule that would return true if object.creatorId === userData.id however if you think about it, it seems pretty dumb... if the monolith already has the info, why not just check for
the general permission Post.Edit and also checking that the user is the creator.
Is there a better approach for this?
I have a simple API which only support one role as of now.
I would like to add an admin role and a normal user. I'm using JWT to authenticate and I have a roleName in my claims.
Now, I would like to have one route for some of my endpoints, but based on what role the user logged in with, the controller corresponding to either admin or user is selected and executed.
Simple example
As a normal user:
/v1/members
returns
{
"memberId": int,
"name: string,
"address": string
}
If the admin user logs in, I would like to have the same url /v1/members, but with another return
eg.
{
"memberId": int,
"name: string,
"address": string,
"socialSecurityNumber": string,
"privatInfo": string,
"notforuser": string
}
I know I could do it in one controller and switch out the roles, but it makes my code very messy and I don't think that's the way to do it.
Best regards from Jens
I'm just gonna answer my own question.
After some hours researching I finally found a solution, that I think works great.
In stead of hooking into the convensions as such I define a middleware, that runs before the MVC actions. It rewrites the local url for the controller and then it hits the correct controller and it's split into separate areas. It works great.
Best regards
Jens :-)
Recently I began to use MeanJs, it's pretty amazing but I don't understand some stuff.
I need to create a simple user management for my backend.
From official blog they say:
New usability features:
Added roles to the User model - the defaults
are ‘user’ and ‘admin’, you can add and remove them as needed.
After a search I found some examples but all of these about meanio, not meanjs, there are a package MEAN-ADMIN in meanio that does it for us but in meanjs I not found.
Someone know the best way to implement a user management? some example?
Thanks guys.
The meanjs generator comes with some basic user roles built in. The roles is an array on the user model.
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
To add a user with the role admin just attach it to the user object before saving.
user.roles = ['admin'];
If you want to use roles apart from admin and user you need to add then to the type enum.
This is probably a question a bit in between SO and UX.se.
I'm implementing a signup/login sytem which allows for multiple ways of authentication: social signups using Facebook, Twitter, Github and a local (username + password) signup.
In the backend I'm having a User model and a Passport model. A User may have multiple Passports, meaning a User may authenticate through different means (e.g.: through local signin,. or through facebook for example)
For good measure: the Passports of a particular User will always be from a different provider (facebook, twitter, local). I.e.: a Facebook-passport, a Local-passport, etc.
This seems like a good way and would allow me to have a User account connected to multiple ways of authentication.
I'm familiar with the security issues this might raise, so for passports to be combined/merged a User has to be logged in to both.
Ok on to the problem. Consider the following flow:
user-a signs up with a provider, say local, with email user-a#gmail.com
user-a signs out (or has it's session expired).
user-a signs in using another provider, say facebook. Chances are the facebook account has a email-record of user-a#gmail.com
Currently, I've defined email to be unique on the User-model. This would mean the above signup would fail, because there's already a User-account that, by means of the local Passport, has the mentioned email-address.
What would be considered a best practice in a situation like this? I trust there must be many implementations floating around that must have seen this problem pop-up.
Options:
Warn the user the authentication isn't possible and mention the user that the current email-address is already registered by means of another authentication mechanism? This would be reasonably user-friendly.
Note that a User-account, by means of a different provider exists with the same email-address and as a consequence merge the new Passport with the User.. I just put this in for good measure: this is a pretty big attack-vector and would allow a user-b to get access to an account by faking the email-address (through a social provider which doesn't do email-validation)
Don't have a uniqueness constraint on <user,email>, but on <passport, email>. This would allow a new User and associated Passport to be created and all goes well. Now the same actual person probably has 2 User Accounts: 1 for each authentication provider. As a next stage allow the User-accounts to be merged, by signing in to both and acknowledging the merge.
I'm leaning towards 3, but 1 is simpler. I'm not sure, what do you think?
Have you encountered this before?
Yes, #3. I have implemented this myself. The concept you're looking at is: Associate multiple SSO accounts. My user structure is as follows:
name : {
first: { type: String},
last: { type: String }
},
emails: [{ type: String, unique: true, 'index': true }], //all known emails as provided by SSO services. we use this to cross ref when the user uses a different SSO to login after initial setup. this avoids account dupes
sso: [{
provider: { type: String, required: true}, //matches the name of passport strategy name employed
userid: { type: String, required: true } //the specific SSO provider userID that's unique in the provider's realm
}]
So, in your auth sequence, you look it up by email OR provider+userid combo, if you don't find the SSO provider, you attach it. The reason for or, someone may update their email but the specific SSO provider ID never changes.
Another common practice (if it makes sense in your app) is to allow the user to "link" SSO accounts. That allows you to handle different email addresses. Example: user FB email is a personal one but in LinkedIn he lists as primary the business one. LinkedIn sadly gives you only the primary via their OAuth2 call.