Java – efficient, database-aware instance-level au

2019-06-27 12:00发布

In a JPA app I have a scenario in which the app is to

list all accounts the given user is authorized to withdraw from

I have the Account entity and a many-to-many table that lists what authorizations each user has on each account – to implement the above scenario, the app currently just inner-joins the two tables – which is quite quick.

Now, I was planning to add an explicit authorization layer (based on apache shiro / spring security / other) to insulate authorization-related logic from the rest of the code, but...

There are some 10k Accounts in the database and the "average" user is granted "deposit" on all of them, "view" on one half of them and "withraw" on just a few.

Does any security framework allow to implement this scenario efficiently?

Ie: is any of them able to "decorate" a JPA query of the type "select a from Account a" (or the equivalent SQL) and thus get the list of accounts without loading all user grants from the database, and by all means, without having to retrieve all accounts?)

3条回答
神经病院院长
2楼-- · 2019-06-27 12:41

Have a look at Apache Shiro.

It allows you to pull in the User authorization once and cache it for the duration of the session. In addition, if all users can VIEW all ACCOUNTS then you wouldn't need to explicitly define this which would significantly reduce the overhead.

If your solution requires realtime access handlers Shiro has a way to reset the Permissions dynamically during runtime too.

Shiro allows you to implement a typical RBAC and define permissions like this:

domain:action:instance

So in your case permissions might look like this for a user:

account:deposit:*  // deposit all accounts
account:view:1111
account:view:2222
account:view:3333 // view on these accounts
account:withdraw:5555
account:withdraw:6666  // withdraw on these accounts

In code you can then do something like this:

if (SecurityUtils.getSubject().isPermitted("account:withdraw:"+account.getAccountNumber() ) {
  // handle withdraw
}

Shiro also has annotation driven permissions for additional abstraction.

EDIT

The Shiro permissions is the end result, not where you start. I used a set of tables representing mappings of the user-to-role and role-to-permission along with other mappings to instance. After AuthN its usually a simple set of queries indexed by the User PK to build up the data structures needed to render the permissions.

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-06-27 13:06

I have a hope that this is one of the possibilities to implement your requirement with Spring-Security.

  1. Write custom org.springframework.security.acls.Permission like ViewAccount,DepositToAccount,WithDrawFromAccount

  2. Write custom org.springframework.security.access.PermissionEvaluator Override hasPermission(Authentication userAuthentication,Object accountObject,Object oneOfThePermission) to check if the user has the defined permission on the accountObject

  3. Get reference to JPA EntityManager in your custom evaluator and cross check/verify in DB with user_id,permission_id,account_id

  4. If the user is 'root' you can staight away return true for hasPermission without verifying with DB.

  5. Annotate your service calls with @PreAuthorize("isAuthenticated() and hasPermission(#accountArgument, 'respectivePermission')")

Refer link for custom implementations of Permission & PermissionEvaluator

查看更多
【Aperson】
4楼-- · 2019-06-27 13:07

If you are using EclipseLink there are a few features for this,

one is the @AdditionalCriteria annotation that allow a filter to be applied to all queries for a class,

http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_additionalcriteria.htm#additionalcriteria

another is EclipseLink's support for Oracle VPD (row level security in the database),

http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing

and finally EclipseLink supports SessionEvents that can allow filter to be appended to any query execution,

http://www.eclipse.org/eclipselink/api/2.4/org/eclipse/persistence/sessions/SessionEventAdapter.html#preExecuteQuery%28org.eclipse.persistence.sessions.SessionEvent%29

查看更多
登录 后发表回答