2

I have a web application that has Users that belong to Companies. A User can only belong to 1 Company at a time and they can manage their own company information. I'm using java spring and I'm following Hexagonal Architecture.

So, I came up to the conclusion that i should check if the User really belongs to the Company at the start of almost every Use case in order to continue with the transaction, because if the User does not belong to the Company -> the transaction must stop. A user can only manage and access information of his own corporation, if the application detects that someone is trying to manage or access something from another company it should throw an unauthorized error (something like "This user is unauthorized to manage information from this company").

In order to do that, I use a path variable to know from which company the user is making the call. I pass this path variable to all the use cases so i can verify if the User really belongs to the Company.


First question: Do i have to check this from the backend? and... Do i have to check this in the use cases?

Second question: If so, how am i suposed to deal with repeated code in multiple use cases? Should i create a function called checkUserCenterAuthorization(username, centername) that does the same in every Use case?

This method [checkUserCenterAuthorization(username, centername)] would actually retrieve the User from database (userDAO.getUserFromUseranem(username)) and check if the attribute Centername of the user is equal to the Centername from the REST call.

Is there anyhting that i'm missing here?

2
  • While this may be a misinterpretation on my part, "user belongs to company" implies that the user does not specifically own or manage the company but rather is added to a pre-existing company, but "can manage their own company" does imply ownership and creation on the user's part. Not saying you're wrong, just pointing out that it leaves some ambiguity/interpretation. – Flater Apr 8 at 0:58
  • yes that may lead to missunderstandings, but i must say that i simplified my problem just so you you can all understand the issue better. Basically i was trying to say that a user is part of a company and he can only access information related to his company. He also have some permisions to manage some things but i found that it wasnt necessary to explain it all. Thanks – Jordi Pagès Apr 8 at 8:59
2

To explicitly answer your questions.

Do i have to check this from the backend? and... Do i have to check this in the use cases?

Yes, with web applications, you'll always want to do authentication/authorization based activities on the backend. This is because you cannot trust web clients to be secure. For instance, in Chrome, a user could use development tools to inspect all of your client code and reverse-engineer your logic for authorization.

If so, how am i supposed to deal with repeated code in multiple use cases? Should I create a function called checkUserCenterAuthorization(username, centername) that does the same in every Use case?

You will indeed need some generic function that will facilitate the authorization logic for all of your use cases, since you've expressed that it applies everywhere. There are some architectural paradigms and frameworks that enable you to inject this logic for all use cases.

One example is a filter pipeline. This paradigm allows you to add a series of request handlers; each handler can make a decision to either pass the request along or directly handle and respond to a request. If you were to use a filter pipeline in your architecture, you could create an authorization handler that will intercept all traffic and short circuit a denial of access if the authorization failed. If the authorization succeeded, this handler could then pass along the request to your various handlers for the various use cases that you have. The important thing to note here is that your particular use cases should not have to call your authorization function; rather, that authorization should happen well before the logic that actually handles your use cases.

Here's a link to how filter pipelines work for ASP.NET: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0

If you're worried about performance of the authorization calls, one thing you could look into is using something like Json Web Tokens with claims to securely append requests with the associated organizational membership. Your authorization filter could then compare this organizational membership claim against the URL path variable that defines the organization that you're accessing.

I hope this helps!

1
  • Thanks, your answer helped me a lot! I'm specially interested on the Json Web Tokens that you've mentioned i think this is the way to go. I also had the same feeling that my particular use cases should not have to call the authorization function, i felt like it didn't belong there. I will search information about all of this thanks. – Jordi Pagès Apr 8 at 9:18
0

You should be able to do this check in your Data Access Layer. You should only need a User ID to perform this check, if your User ID's are globally-unique.

If all of your "Use Cases" use this data layer, you will only have to check once in each method or endpoint of your Data Access Layer.

2
  • I've thought about putting this check it in the persistence layer, but i also thought that it didn't belong in that layer. If i understood your answer correctly, you are saying that this "logic" should be in my User Data Access Object? (UserDAO is one of my outPorts interface that my persistence adapter implements). And does this confirm that in the persistence adapter i can have some kind of logic too and it's not only for retrieving objects from database? – Jordi Pagès Apr 7 at 20:25
  • There's no right or wrong way to do this. There is only the way that best meets your requirements. There are, of course, better or worse ways depending on what your objectives are. So if it makes sense to put your checks in the "UserDAO", by all means put them there. – Robert Harvey Apr 7 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.