How do you weave Authentication, Roles and Securit

2019-03-10 02:21发布

问题:

How do you implement Roles and Security in your C# Domain Driven Design projects? We have some debate raging on whether it should be implemented by the calling application (ASP.NET MVC) or in the Domain Model itself (model entities and services). Some argue that it should be in the web site itself since that's where the authentication already exists. But that means you have to re-implement security every time you integrate with the core business systems.

As an example: an Admin should be able to do pretty much any action in the system such as edit and deleting records (i.e. they can delete an user's order). An User on the other hand should only be able to edit and delete their own records (i.e. they can add/remove items from their shopping cart).

By the way, here is a nice thesis on the topic which covers 7 different scenarios regarding DDD & Security:

Security in Domain-Driven Design

  • Chapter 4 Security service design scenarios
    • 4.1 Scenario 1: Security service as regular service
    • 4.2 Scenario 2: Security embedded in the UI
    • 4.3 Scenario 3: Security service encapsulating the domain model
    • 4.4 Scenario 4: Security service as a gateway for the UI
    • 4.5 Scenario 5: Security service as an adapter for the UI
    • 4.6 Scenario 6: Security service integrated by AOP with adapters
    • 4.7 Scenario 7: Security service integrated with AOP

I would personally lean towards AOP using PostSharp, but not having done much with it before, I'm hesitant to take the leap.

回答1:

Don't forget that the runtime already has an abstracted security/user system built in - the principal (see this existing answer - note that GenericIdentity is just one option; it is pretty trivial to write your own).

Your UI can handle creating and assigning the principal based on the specific implementation (indeed, IIRC ASP.NET and WCF do this automatically, or for winforms/wpf you can use the windows identity, or (via a web-service) the same ASP.NET login).

Your business logic then just checks Thread.CurrentPrincipal; from this you can get the name, the authentication method, and check for roles (without needing to know how roles are implemented).

The runtime also provides inbuilt checks:

    [PrincipalPermission(SecurityAction.Demand, Role = Roles.Admin)]
    public void Foo() {...}

(where Roles.Admin is a string constant of your role name) This will check access automatically, throwing a SecurityException if not in the role. You can also check via code (useful if the role isn't fixed at compile time).

Obviously your UI should check roles (to disable/hide functionality), but it is good to have the business code enforce the roles without needing to know about the UI.

(added)

I should mention that GenericIdentity is handy for unit tests. Of course, you could role your own security API, and nobody will stop you...