Filtering Authorization Method Level#
Filtering Authorization Method Level In Spring Security#
- If we have a scenario where we don't want to control the invocation of the method but we want to make sure the parameters send and received to/from the method need to follow authorization rules, then we can consider filtering.
- The
@PreFilter
and@PostFilter
annotations are used to filter lists of objects based on custom security rules we define. @PreFilter
defines a rule for filtering a list that is being passed as an input parameter to the annotated method. If the evaluated value is true, the item will be kept in the list. Otherwise, the item will be removed.- For filtering the parameters before calling the method we can use
@PreFilter
as below.
ContactController.java | |
---|---|
1 2 3 4 5 |
|
-
As you can see in the example above, we will use
@PreFilter()
to check the subject field ofContact
object is equal with theHello
value or not. If the value of subject field is not equal withHello
, theContact
object will be removed out of the list. -
@PostFilter
defines a rule for filtering the return list of a method, by applying that rule to every element in the list. If the evaluated value is true, the item will be kept in the list. Otherwise, the item will be removed. - For filtering the parameters after executing the method we can use
@PostFilter
as the example below.
ContactController.java | |
---|---|
1 2 3 4 5 |
|
- We can use the
@PostFilter
on the Spring Data repository methods as well to filter any unwanted data coming from the database. It means, after queryingContacts
from the database. OnlyContact
has contactName isHan
will be kept in the return list. Otherwise, the item will be removed.
PreFiltering And PostFiltering Examples#
Database Tables#
- We will create
contacts
table which will contain some columns such ascontactName
,contactEmail
,subject
andmessage
. So, let's run the SQL script below to create the table.
1 2 3 4 5 6 7 8 |
|
Entity#
- Then in we create the
ContactEntity
class as below:
ContactEntity.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 |
|
Repository#
- Let's create
ContactRepository
below.
ContactRepository.java | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
Service#
- Next, we need to create a service class which call to
ContactRepository
for gettingContactEntities
and map them intoContact
DTOs.
ContactService.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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
- The
Contact
DTO will look like below.
Contact.java | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Controller#
- Finally, we will create a new api in the
ContactController
for gettingContacts
by customerId.
ContactController.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 35 |
|
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@PreFilter
&@PostFilter
annotations. - Now, let's try to add
@PreFilter
into theContactController
as below.
ContactController.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 35 36 37 |
|
-
As you can see the
@PreFilter
will require all input object have to contain subject equalHello
value. If not it will be removed out of the list automatically. -
Then in the
ContactService
. We will add@PostFilter
as below.
ContactService.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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
- As you can see the
@PostFilter
will require all object have to contain contactName equalHan
value. If not it will be removed out of the list automatically.
Testing#
- Now, let's start our Spring Security application and call api
/v1/user
with user emailhan.do@example.com
for login and get the jwt token.
- Then we will use this jwt token to call POST
/v1/contact
for creating Contacts with request's body as below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
- So, with this request body and the
@PreFilter
that we set up, there are only two first contacts that will passed the@PreFilter
and saved into the database because they have subjectHello
. Let's execute the request and you will received the result as below.
-
As you can see, only two first contacts are saved in the database.
-
Then we will use the jwt token to continue to call GET
/v1/contacts
for getting Contacts. With the current set up for@PostFilter
we will only received the first Contact record in the database because on it has contactName equalHan
. Let's execute the request and you will received the result as below.
Conclusion#
@PreFilter
and@PostFilter
are useful in some special case and easy to use. It helps developers saving for time for writing codes to checking data. However, If we use it for a very large list so it can be a performance issue and inefficient.- For example if we have thousands of
Contacts
in our database and we want to retrieve the fiveContacts
that are currently have contactName withHan
value. If we use@PreFilter
the database operation will fetch all theContacts
first, and iterate through all of them to filter out the ones that have not contactName withHan
value.