Spring Security

Ferhat Bedir
emlakjet
Published in
7 min readApr 17, 2024

Hello everyone. In this article, we will talk about spring security.

What is the security?

It which protects our business logics, sensitive datas etc.. is a layer in our application.

Why is security important?

It is important. There are a few reason for this.

  • User Security
  • Corporate Security
  • Legal and Regulatory Compliance
  • Data Integrity and Reliability
  • Prevention of Service Disruptions

What is the Spring Security?

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Spring Security is a framework that focuses on providing both authentication and authorization to Java applications.

Of course we can create our own custom security layer but, this is very risky. Because, we always have to follow new security holes and we have to take a precaution for them. Spring Security handles those for us.

Why should we use the spring security?

  • Spring Security built by a team at Spring who are good at security by considering all the security scenarios. Using Spring Security, we can secure web apps with minimum configurations.
  • Spring Security handles the common security vulnerabilities like CSRF, CORs etc. For any security vulnerabilities identified, the framework will be patched immediately as it is being used by many organizations.
  • Using Spring Security we can secure our pages/ API paths, enforce roles, method level security etc. with minimum configurations easily.
  • Spring Security supports various standards of security to implement authentication, like using basic authentication, JWT tokens, Auth2, OpenID etc.

How does it work?

internal flow

Spring Security Filters: The filters intercept all requests whether authentication is required or not. If authentication is not required, you can access the resource. However, when authentication is required, there are two options. If the user has logged in before in the system, they can access the resource. Otherwise, the user is directed to the login page. You can read more about filters here. Here are some examples of filters:

  • AuthorizationFilter
  • DefaultLoginPageGeneratingFilter
  • ChannelProcessingFilter
  • SecurityContextPersistenceFilter
  • UsernamePasswordAuthenticationFilter
  • LogoutFilter
  • SessionManagementFilter

Authentication: Authentication is the core standard for storing authenticated user details inside the Spring Security framework. For instance, the UsernamePasswordAuthenticationFilter extracts the username and password from the HTTP request and prepares an Authentication object. Additionally, custom logics can be created.

Authentication Manager: Once a request is received from the filter, the AuthenticationManager delegates the validation of user details to the available authentication providers. Since there can be multiple providers within an app, it is the responsibility of the AuthenticationManager to manage all available authentication providers.

Authentication Provider: It is an interface that contains all the core logic for validating user details for authentication. You can create your own provider by implementing this interface. Also, TestAuthenticationProvider can be used for unit test.

UserDetailsManager / UserDetailsService: It helps in retrieving, creating, updating, deleting the User Details from the DB/storage systems.

PasswordEncoder: Service interface that assists in encoding and hashing passwords. NoOpPasswordEncoder is used by default. However, this encoder is not secure because it compares passwords as plain text. That is why you shouldn’t use it in production. Here are some examples of encoders:

  • NoOpPasswordEncoder
  • StandardPasswordEncoder
  • Pbkdf2PasswordEncoder
  • BCryptPasswordEncoder
  • SCryptPasswordEncoder
  • Argon2PasswordEncoder

SecurityContext: Once the request has been authenticated, the Authentication will usually be stored in a thread-local SecurityContext managed by the SecurityContextHolder. This aids in handling subsequent requests from the same user.

How to use it our project?

First of all, the dependency that is below should be added to the project. Then, when you start the project, Spring Security will start to work.

<!--for maven-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- *-*-*-* -->


//for gradle
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security'

When you send a request to the application, you will be directed to the login page. This is because Spring Security protects our services.

loginPage

If you don’t define a user for Spring Security, it creates a user for you. This user has a username and password. The default username is ‘user’, and you can find the generated password in your application’s console log. The password changes every time the application restarts.

generatedPassword by the spring security

We can create a user for Spring Security in two ways. The first way is to define the user information inside the ‘application.properties’ or ‘application.yml’ file. The second way is to define the user information inside the security config class. When the user information is defined inside the config class or config file, it can be used at all times.

class config
file config

When the Spring Security is implemented, it applies the default configurations. Let’s analyze the default configurations.

  • In the first row, authentication is required for all requests.
  • In the second row, the form login page is active.
  • In the last row, basic authentication is active.

Code example.

Let’s analyze some of the Spring Security configurations.

How to create custom UserDetailsService?

You should create a class that implements UserDetailsService and override the loadUserByUsername method. In this class, you should retrieve user information from the data source and create a new user based on this information. Code example.

How to use BCryptPasswordencoder?

The BCryptPasswordEncoder should be created in the WebSecurityConfig class in the project. This is enough to use BCryptPasswordEncoder. Code example.

How to create a custom authentication provider?

You should create a class that implements AuthenticationProvider and override all necessary methods. You can implement your own custom business logic in the class. Code example.

How to configure CORS and CSRF config?

CORS and CSRF configs can be set inside the webSecurityConfig.

For CORS configuration, you can define allowedOrigins, allowedMethods, allowedCredentials, allowedHeaders, and maxAge. ‘*’ represents all methods, all origins, or all headers. Alternatively, you can define them individually.

For CSRF configuration, it only works with the HTTP Post method. If you want to ignore CSRF for a specific path, you can use ignoringRequestMatchers. ‘CookieCsrfRepository.withHttpOnlyFalse’ configuration is used to maintain CSRF protection. It disables the HTTPOnly attribute of CSRF tokens generated to prevent CSRF attacks. This prevents access by JavaScript code in the browser, providing an additional layer of protection against CSRF attacks.

Code example.

How to add Role or Authority for specific path?

Roles and authorities can be assigned to specific paths. This is easily achieved with Spring Security. Permissions can be granted to users based on their roles, while permissions for specific pages can be granted based on authorities. Role names must start with the prefix ROLE_. There are no specific rules for authority names. Code example.

How to create a custom filter?

You should create a class that implements Filter and override the doFilter method. You can implement your own custom business logic in the class. We can add three type filter to the spring security config. These are ‘addFilterBefore’, ‘addFilterAfter’, ‘addFilterAt’.

addFilterBefore works before the validation.

addFilterAfter works after the validation.

addFilterAt works validation time.

There can be more than one custom filters that are same types, in this case their running order can be defined by the spring security.

Let’s compare the GenericFilterBean and OncePerRequestFilter

  • Inheritance:
    GenericFilterBean: Base filter class.
    OncePerRequestFilter: Applies filter logic only once per request.
  • Execution Frequency:
    GenericFilterBean: Filter logic is reapplied for each HTTP request.
    OncePerRequestFilter: Applies filter logic only once per request, not repeated for each HTTP request.
  • doFilter Method:
    GenericFilterBean: Requires overriding the doFilter method.
    OncePerRequestFilter: Contains a specialized doFilterInternal method.
  • Performance:
    OncePerRequestFilter: Designed to enhance performance by applying filter logic only once.

Code example.

How to use JWT(Json Web Token) and method level security?

First of all, the dependencies that is below should be added to the project.

<!--for maven-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<!-- *-*-*-* -->


//for gradle
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.12.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.12.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.12.5'

If you want to use method level security, you can add the config inside the project ‘@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)’. And then you can use it in the project.

With this configuration, you can prevent creating a customer with the name ‘test’. This security configuration is straightforward and easy to understand. Code example.

You can see all the code for the examples here.

Thank you for reading..

--

--