Closed rockfordlhotka closed 7 months ago
Just thinking this through and here is my take on this.
In the sample at the moment, the page (actually the client side route) is the thing that's authorised. Conceptually a blazor page may or may not contain any Csla objects. Or it could contain multiple (for example displaying different forms or lists on different tabs). Therefore I think the current page level authorisation check that's in place in the sample, by not being bound to any particular Csla root object is as it should be.
So then the question is, how do we render say an EditableRoot on a page, and have that view automatically check for CanEdit permissions etc and display display appropriate bot authorised message based on the EditableRoot authorisation rules.
Well.. I'm not sure of the best approach.. yet. But I'm thinking roughly:
I see there is an EditForm already developed in the sample. If this was wrapped in such a component above then the whole form would not be displayed if the use didnt have edit permission. However what about field level authorisation- would the edit form need to be extended to do authorisation checks on each field? It would it be down to the developer to provided different display templates for fields that fail authorisation? I'm not clear on this more thoughts needed
I understand what you are saying, but there's a philosophical core to CSLA, which is that all rules are centralized in the business layer.
I'm thinking forward to the ProjectTracker Blazor UI I'll build, and in ProjectTracker at no point are there rules outside the business layer. So, for example, whether a user is allowed to navigate to a form/page/screen that edits a domain object, it is a rule from that domain type that is used to tell the UI if the user has permission.
The idea is that when such a rule changes (and authz are rules), a dev shouldn't have to hunt through the business layer and the entire UI to see if a role/claim/permission was met. They go to the business layer, change it, and know that the change automatically impacts all types of app that use the business layer.
In other UI technologies I've always created some UI helpers - usually extending existing platform functionality. For example, in MVC there are authorization helpers that can be used in place of the standard ones - the difference being these helpers rely on the business layer for the rules.
It isn't enough to let the user navigate somewhere and tell them they can't see it - that's cruel! 😄 It is necessary to disable or hide the navigate element so they know they can't go there.
I understand, but im not sure fully.. yet! 😁 perhaps allow me to divulge my thinking a bit more to see if we are actually agreeing!
Not all pages in my blazor SPA may be CSLA driven. For example if I want to add simple content page to my site - and authorise access to it based on the logged in users roles (e.g "members" can access support docs page) - I shouldn't be forced to create a CSLA business layer for that addition to my site. My philosophy then is that my site should work like a normal blazor website first - but then allow me to add Csla driven UI's (i.e bound to Csla objects) where I need to.
I believe the blazor "page" level authorisation is not something csla need concern itself with. It's the actual point where I want to include a Csla driven portion of UI on a page that I care about Csla authorisation checks happening (I.e at the blazor component level) and the ability to control what to render to a non authorised user. Like you say - it's cruel to allow users to navigate to a page and then not see anything. Applying an authorise attribute to an entire page for the blazor router to check on navigation does not help you with that problem of not rendering the link in the first place. Likewise if you have the thing to not render the link in the first place then you can also use that same thing to add on the target page to not display that pages actual content if the user isnt authorised- so again that takes the blazor router and page level authorise attribute out of the equation.
I create blazor pages to reflect the url navigation space I want for my site - not as a 1 to 1 mapping exercise for Csla use cases. To elaborate on this point a little - it's my view that I should be able to build the equivalent of the entire Csla project tracker application, in one single blazor page using blazor components to achieve that- if that's how I decide I want my sites url space. At the page level I'd not apply any authorisation. Or i'd split it into two pages, with the /login page not having any authorisation and the main page requiring authenticated user. The UI I render on that main page will want to take into account Csla authorisation rules so I cant see menu items for things I shouldn't have permission to access (probably a good first problem to solve) but when I do click on a menu item - it wouldn't navigate the user off to any other page it would stay on the same oage and display the relevent Csla form in a modal. Note the url has not changed, the page has not changed, the blazor router has not been involved, but still I need that Csla ui in the modal to now honour the Csla auth rules when l launch the modal). Page level authorisation is not useful here.
Saying all of that, as a thought experiment suppose you did have a page like /EditUser that you did want to authorise based on Csla auth rule. If you navigate to that page the blazor router will perform the check and display its NotAuthorised template content when auth failed. Anyone can copy and paste in the URL to visit that page. In terms of not displaying a link to the page in the first place, based on some Csla auth rule check, my preference is to get the in built in AuthorizeView component to work with Csla business object type auth rules. Now this works but suppose we now remove the page level authorize attribute - the blazor router now does not do any authorization check on navigating to that page (which is what I am suggesting) but once on that /EditUser page there is the AuthorizeView that conditionally displays the csla ui component based on the auth check. You end up with a similar effect but its now more flexible - because now other components / parts of that target page can still be rendered to the user if their auth requirements are met.
Given the above if I was to pursue this line of thinking I'd do this:
<AuthorizeView Policy="csla-user-edit">
<p>You can only see this if you satisfy the policy.</p>
</AuthorizeView>
They policy name would use some form of convention - containing enough info for the service to resolve the Csla business object type, and rule that needs to be checked, and build the authorisation policy to be consumed. In the case above its going to build and return an Authorization policy that checks that the current principal can edit the User business object type.
I think that's it? This component is pretty flexible. With this one native AuthorizeView component, it can be used to conditionally display links and menu items based on Csla type auth rules. Likewise on pages and within modals (for example, around the EditForm in the current sample) it can display alternatice content if the user isnt authorised.
I think we're on the same page - we've both been authorized 😄
I'm not trying to force the idea that every page uses CSLA authorization. But it needs to be an option, because if someone does build a business app - such as porting from WinForms to Blazor - it needs to be possible to leverage rules from the business layer for page, navigation, display/hiding controls, and enabling/disabling controls. Stuff like that.
I think creating a CSLA authorization policy (or policies?) that use per-type rules is absolutely the right step.
@rockfordlhotka any progress on this one?
Just dumping some thoughts here on implementation:
This will be demonstrated in ProjectTracker, and I don't plan to change the simpler example.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
@dazinator updated the
BlazorExample
sample to include authentication and some authorization.I believe the authorization relies on Blazor UI support directly against the user's principal, and doesn't leverage authorization rules from the business layer.
Ideally the authorization would rely on per-type rules implemented in the
PersonEdit
class to determine whether the current user is authorized to view/edit a person.