Invocation Authorization Method Level#
Invocation Authorization Method Level In Spring Security#
- Using invocation authorization we can decide if a user is authorized to invoke a method before the method executed (
preauthorization) or after the method execution is completed (postauthorization). - For filtering the parameters before calling the method we can use
Prefilteringwith annotation@PreAuthorize. See the sample configuration below.
| LoanService.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
- For applying
postauthorizationrules we can use annotation@PostAuthorize. Below is the sample configuration.
| LoanService.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 | |
- When implementing complex authorization logic, we can separate the logic using a separate class that implements
PermissionEvaluatorand override the methodhasPermission()inside it which can be leveraged inside thehasPermissionconfiguration. - You should note that when applying the
@PostAuthorizefor the method and the user is not authorized to invoke that method. So the method will still be executed the business logic present inside it. Like it will commit the transactions to database, but while retaining the values to the user, if the alteration rules are not satisfying, then it will throw 403 error, which is an exception. But please don't expect database transactions to be rolled back, because even if you keep adding transaction annotation on top of the method, the committee transactions to the database will no be rolled back.
PreAuthorization And PostAuthorization Examples#
Database Tables#
- We will create
loantable which will havemanyToOnerelationship withcustomerstable. It means one customer can have many loans. Theloantable will contain some columns such asdescription,loan,paid,start_dateandcustomer_id. So, let's run the SQL script below to create the table.
1 2 3 4 5 6 7 8 9 10 11 | |
- Now for the current customer with email
han.do@example.comin thecustomerstable we will use the SQL statements below to set a loan for this customer.
1 2 3 | |
- So, after all our table will have data as below:
customers table
| id | password | role | |
|---|---|---|---|
| 1 | duc.nguyen@example.com | 12345 | admin |
| 2 | han.do@example.com | $2a$12$V.A53NkiPnA45W44aRYi2OLwUbbu08aDoY409/SKY/bT7cdF1PpLO | admin |
| 3 | john.wick@example.com | $2a$12$V.A53NkiPnA45W44aRYi2OLwUbbu08aDoY409/SKY/bT7cdF1PpLO | user |
roles table
| id | role | customer_id |
|---|---|---|
| 1 | ROLE_ADMIN | 2 |
| 2 | ROLE_USER | 3 |
| 3 | ROLE_USER | 2 |
loan table
| id | description | loan | paid | start_date | customer_id |
|---|---|---|---|---|---|
| 1 | loan for buying car | 5000.0 | 2500.0 | 2022-09-01 12:12:12 | 2 |
Entity#
- After updating the database tables, we will also extend our
CustomerEntitywithLoanEntity. So inCustomerEntitywe will have a list ofLoanEntitywith@OneToManyrelationship.
| CustomerEntity.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
- Then in we create the
LoanEntityclass as below:
| LoanEntity.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
Repository#
- Let's create
LoanRepositorybelow for queryLoanEntitiesby customerId.
| LoanRepository.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Service#
- Next, we need to create a service class which call to
LoanRepositoryfor gettingLoanEntitiesand map them intoLoanDTO.
| LoanService.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
- The
LoanDTO will look like below.
| Loan.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Controller#
- Finally, we will create a new api in the
LoanControllerfor gettingLoansby customerId.
| LoanController.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Configuration#
- Now, to use Method Level Security we will enable it by add the annotation
@EnableGlobalMethodSecurityinto the main class as below.
| CustomDefaultSpringSecurityApplication.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
- The param
prePostEnabled = truemeans we enables Spring Security@PreAuthorize&@PostAuthorizeannotations. - Now, let's try to add
@PreAuthorizeand@PostAuthorizeinto theLoanControlleras below.
| LoanController.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
- As you can see, both Apis will require user has role
ADMINto get the resource. However, with@PreAuthorizethe Spring Security will check the authorization before the code in the method is executed. For@PostAuthorizethe Spring Security will check the authorization after the code in the method is executed.
Testing#
- Now, let's start our Spring Security application and call api
/v1/userwith user emailhan.do@example.comwhich hasADMINrole for login and get the jwt token.
- Then we will use this jwt token to call
/v1/loanand/v1/loan/customers/{customerId}for@PreAuthorizeand@PostAuthorize. You will receive 200 OK status as below.
- Next, we will try to call api
/v1/userwith user emailjohn.wick@example.comwhich hasUSERrole for login and get the jwt token.
- Then we will use this jwt token to call
/v1/loanand/v1/loan/customers/{customerId}for@PreAuthorizeand@PostAuthorize. You will receive 403 Forbidden status as below.
- However, if you put a debugger in the
LoanServicewhich is call by/v1/loan/customers/{customerId}api with@PostAuthorize. You will see the code of this api will be executed and spring security only check the Authorization after the api is going to response.






