Building an application without security is like building a house without doors
– Unknown
When I was in my college days, all I used to care about was creating an application that would bring a change. My thought process was limited to the development of the UI + Backend + Database. I even created a website that would register users, retrieve logged-in users, and book bikes and cars for them. It was a great portal to book and track your bookings after logging in. But all this changed when I came across this subject in my third year based on networking.
What changed in my perspective was the following :
- I came to know that the data will travel from one router to another before reaching the actual server. For example - let's say the server is in the USA, and I send a request from India. It will pass through a lot of networking devices before reaching the actual recipient.
- This means that there might be a scenario, where someone intercepts this data in the middle, gets the username and password, and use it to impersonate that user.
- I may send an encrypted text, but if it's intercepted, still the hacker can impersonate me or the user trying to log in by sending that encrypted text to the server and getting the data from it.
Take a moment to think about it. Is encryption enough? Can't he just use the encrypted text instead? The hacker anyways does not care what password you put in as long as he can get what he desires.
This is just one example, you can think of a lot more along these lines.
So now the question is -
What can we do to remediate this?
Spring Security To The Rescue !!!!!
Spring Security is a powerful and highly customizable authentication and access-control framework.What it would basically do is provide you with methods and ways to authenticate as well as authorize the user. I will talk about Authorization in a little while, right now let's concentrate on the authentication part.
If you understood the above challenges correctly, you might think -
HOW?? will spring security do it? Is it going to provide a security guard on each networking device from where your data passes? Hmm.... nice thought, but you know security guards can be drugged sometimes forcefully but majorly voluntarily.
The answer is NO!. This won't be a practical solution. But what we can do is check for any disruption in the data sent from client to server. Basically saying checking if the data sent for authentication from the client to the server was actually sent by the client.
What I am basically trying to say is: If I send a request from India from my computer, or we can call it a client, We can send something to the server which would tell the server that we sent it.
By now I am sure you might have understood the challenges we face. I am still going to point them down just in case we forget what we are talking about. The questions our server will ask are the following :
- Is the request sent to me from the actual user?
- Is the request sent to me not tampered with?
The Real Question is HOW?
There are many ways to do this in the context of spring security. I will cover each way in terms of authentication and we will see how each can be utilized in your applications.Spring Security Using JPA
If you are unfamiliar with JPA, you can go to this link and have a quick look -
https://www.tutorialspoint.com/jpa/jpa_introduction.htm#
In basic terms, a JPA is a layer between your application and database, using which you can write code in the application language such as java and interact with the database.
For example, if we want to get a user by its username from the database, we would use JPA inbuilt methods like findUserByUsername() and get the username.
I would not go into much detail on JPA as this blog is more inclined toward security.
FLOW :
The flow of this application is simple.
- User enters credentials and hits submit in the User Interface Form.
- Data reaches the server and passes through the spring security filters.
- We will create a class for the authentication of this data through JPA, which we will see in a while.
- Spring security will authenticate this user with the database using JPA and if the user is authenticated, it will save the user in its context, and then for example, if a user visits any other part of the application, the server can check if the user is an authenticated user or not using this context.
Implementation :
Create a project using this link. In dependencies, add the following dependencies
Once this project is ready, download it and unzip it and import it as a maven project into your IDE. I will be using eclipse for this one.
Let us first create a controller class with some APIs.
![]() |
| Code For Controller |
This controller has three endpoints, which would return three different HTML when they are called by the User Interface. If you know how to create a rest API, this would look pretty simple. If not, you should take a look at how we can write a simple API using java and spring boot.
But now, We would only want an authenticated user to be able to access these API Endpoints.
For this, We will create a security configuration class, where all the magic of spring security will happen.
What are we doing here?
Before I explain that, there is something really notable we must know -
The Authentication part where we compare the user details which came from UI with what we already have in our databases will always be done by spring security, what we can change is the way, in which the information is retrieved from our database or any third-party service for comparison.
In our case, we are creating a user details service and auto-wiring it to this class.
Then, we tell spring security that whatever data comes from the UI or the consumer's end, we want you to check that data through our custom-made userDetailsService.
Setup JPA and Custom UserDetails class
Now, We will set up our JPA. For this, I am using MySQL as a database.
We will create a database using the command
<create database spring security> in MySQL.
Do it however it suits you.
Then, we will go to the application.properties file, presented under the resources folder of our project, and type in some configurations that our application will use to connect to the database.
After this, the application will know where and how to connect to our database.
Next, we create a repository using the inbuilt JPARepository class, which provides us with methods such as getUserByUsername, etc which will then be automatically converted to actual SQL queries by the JPA.
As we can see, this Interface extends JPARepository and also takes in a generic. This generic first parameter is the class, on which this repository will perform operations such as getUserByUsername(). Then the second parameter is the type of key being used in the class/table. We see the first parameter is User. But who defined this User class?
This will also be defined by us as an entity class. I will not go into JPA in detail but the entity class is mapped to a table in MySQL in simple language.
Our User.java class will look like this :
In the repository above, we have also defined our own method :
Optional<User> findByUserName(String userName);
We did this to so that when we send a userName to this method, we are returned with an Optional of type User. Why we did it, will be explained when we write our UserDetailsService.
What is UserDetailsService?
This is the service, which will tell spring security, how the data is to be retrieved. You might think that this data implementation may differ from person to person. For example, some people might want to send just user name and password, while others may send a username, password, phone number, etc.
You are right, spring security does have a standard class for this very reason.
Its name is - UserDetails which is present in org.springframework.security.core.userdetails package.
The class would look something like this :
Ok Ok, Calm down. It's pretty simple.We annotate this class with a @service annotation to let the spring container know of its presence.We then implement the UserDetailsService Interface. This interface does two things for us :- It will help our custom class to be autowired to the previous configuration class.
- It will add a method called loadUserByUsername.
The loadUserByUsername(String userName) takes a parameter called username, which is supplied by spring to this method from the data which the user sent from the actual user interface. Now in the next line, we use the JPA repository to fetch us the data using findByUserName(userName). If the user is found, it returns a User class type of optional which we then convert according to our custom class which is MyUserDetails using its constructor.
Why did we convert to MyUserDetails?We did this because as we talked about above there should be a generalized class present, this generalization is required so that the data which is retrieved is in the same pattern as required by spring security to read and evaluate it with the data user sent. This class MyUserDetails will implement UserDetails Interface. Take some time to understand it through the code or else code it yourself for better understanding.
Notice what we are trying to achieve here is to convert or map the User object we retrieved from our database to the UserDetails object required as spring can only read objects of UserDetails class.
Great! Once this is done you can start your spring boot either through IDE or you can visit the internet to check how to run the spring boot application in your desired platform.
Once you are there, you will be presented with a form, provided by spring security to enter your username and password. Note whatever we enter here should be present in the User table of our database for spring security to compare. Once this is done, you will see that you can easily access the URL: localhost You can also put in a debugger in your respective IDE to see how all this works.
- It will help our custom class to be autowired to the previous configuration class.
- It will add a method called loadUserByUsername.
The loadUserByUsername(String userName) takes a parameter called username, which is supplied by spring to this method from the data which the user sent from the actual user interface. Now in the next line, we use the JPA repository to fetch us the data using findByUserName(userName).
If the user is found, it returns a User class type of optional which we then convert according to our custom class which is MyUserDetails using its constructor.
Why did we convert to MyUserDetails?
We did this because as we talked about above there should be a generalized class present, this generalization is required so that the data which is retrieved is in the same pattern as required by spring security to read and evaluate it with the data user sent. This class MyUserDetails will implement UserDetails Interface. Take some time to understand it through the code or else code it yourself for better understanding.
Notice what we are trying to achieve here is to convert or map the User object we retrieved from our database to the UserDetails object required as spring can only read objects of UserDetails class.
Great! Once this is done you can start your spring boot either through IDE or you can visit the internet to check how to run the spring boot application in your desired platform.









Comments
Post a Comment