In this post I want to explain how Spring Security can be customized since it seems to be difficult to find any solid documentation around this available on internet. I am going to use a custom API Key based authentication example to demonstrate how Spring Security can be configured for your needs.
I am going to create three things to get this done.
- A Token to hold the
principal
and thecredentials
- A Filter to create the aforementioned Token from the request, authenticate that using the
AuthenticationManager
and place theAuthentication
in theSecurityContextHolder
. - An Authentication Provider to be used by the
AuthenticationManager
to authenticate the Token.
I will begin by creating a Spring Boot Project using Spring Initializr. I will need two dependencies here; Web
and Security
.
Once I have the project running on my favorite IDE, I am going to create two packages called config
and security
. I will use the former to keep my Security Configuration file and the latter to keep the Token, Filter and the Authentication Provider. You really don’t have to stick to this package structure. You can do whatever you want with your package structure as long as that makes sense to you and the folks writing the code.
Next Steps
Create the Custom Authentication Token
The Custom Authentication Token will hold the apiKey.
Create the Custom Authentication Provider which supports ApiKeyAuthenticationToken to authenticate the Custom Token we just created
I will first add the my API Key to application.properties
.
The Custom Authentication Provider will check if the API Key is valid. If it is not, the Authentication Provider will throw an Exception. In a Production Application you may create a Custom Exception which will be handled gracefully with the correct HTTP response code.
Create the Filter which creates the Token and asks the Authentication Manager to authenticate that Token
Update the Security Configuration
The Security Configuration class that extends WebSecurityConfigurerAdapter
annotated with @EnableWebSecurity
.
Section 1 disables Basic Authentication( which is enabled by default), CSRF and Cookies( you will not see the JSESSIONID now) for all requests.
Section 2 permits all traffic to public endpoints.
Section 3 adds our custom filter for all protected endpoints.
I will use the code snippet below to configure Authentication Manager to use the Custom Authentication Provider.
Write the Controllers
I will now create another package for controllers called controller
and write two GET
methods there.
Testing
The public endpoint will respond without any API Keys.
The protected endpoint will give an access denied error if the API Key is not sent in the Headers.
The protected endpoint will throw an error with the message “Invalid API Key”. Note that the HTTP Error code is 500. That needs to be handled with an Exception Handler.
The protected endpoint will respond if the correct API Key is sent.
The Source Code is available here.