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
Prefiltering
with annotation@PreAuthorize
. See the sample configuration below.
LoanService.java | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
- For applying
postauthorization
rules 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
PermissionEvaluator
and override the methodhasPermission()
inside it which can be leveraged inside thehasPermission
configuration. - You should note that when applying the
@PostAuthorize
for 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
loan
table which will havemanyToOne
relationship withcustomers
table. It means one customer can have many loans. Theloan
table will contain some columns such asdescription
,loan
,paid
,start_date
andcustomer_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.com
in thecustomers
table 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
CustomerEntity
withLoanEntity
. So inCustomerEntity
we will have a list ofLoanEntity
with@OneToMany
relationship.
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
LoanEntity
class 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
LoanRepository
below for queryLoanEntities
by 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
LoanRepository
for gettingLoanEntities
and map them intoLoan
DTO.
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
Loan
DTO 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
LoanController
for gettingLoans
by 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
@EnableGlobalMethodSecurity
into 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 = true
means we enables Spring Security@PreAuthorize
&@PostAuthorize
annotations. - Now, let's try to add
@PreAuthorize
and@PostAuthorize
into theLoanController
as 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
ADMIN
to get the resource. However, with@PreAuthorize
the Spring Security will check the authorization before the code in the method is executed. For@PostAuthorize
the 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/user
with user emailhan.do@example.com
which hasADMIN
role for login and get the jwt token.
- Then we will use this jwt token to call
/v1/loan
and/v1/loan/customers/{customerId}
for@PreAuthorize
and@PostAuthorize
. You will receive 200 OK status as below.
- Next, we will try to call api
/v1/user
with user emailjohn.wick@example.com
which hasUSER
role for login and get the jwt token.
- Then we will use this jwt token to call
/v1/loan
and/v1/loan/customers/{customerId}
for@PreAuthorize
and@PostAuthorize
. You will receive 403 Forbidden status as below.
- However, if you put a debugger in the
LoanService
which 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.