How to do user authorization in Spring Boot?

Let’s say you have created a Spring Boot application and protected it using a login form.

If any user tries to access your application they are presented with a login form .

If the user name and password match , they are allowed to access your screens.

If you want to know how to implement this in Spring Boot , here is a simple example:

https://fullstackdeveloper.guru/2020/06/05/how-to-do-user-authentication-in-spring-boot-using-postgresql-database/

Now , let’s say you want to protect certain screens and allow only specific users to access them.

In other words you want to authorize your application.

Users will be able to access only those screens for which they have access for.

How to do this in Spring Security?

Adding to the steps mentioned in the above post to implement authentication , you need to follow the below steps:

First , you need to associate a role with the user.

Second , you need to configure the access rights in your configuration file.

Let’s see a simple example to implement this:

STEP1: Associate a role with the user.

To do this add a field name “role” to your “User” entity class created in the above example.

Here is the updated User entity class:

package com.springboot.dbauthentication;

import java.util.*;

import javax.persistence.*;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
@Table(name = "user_table")
public class User implements UserDetails {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 
	 */

	@Id
	private Integer id;

	private String username;

	private String password;

	private String role;

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}

	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {

		List<SimpleGrantedAuthority> authorities = new ArrayList<>();


		authorities.add(new SimpleGrantedAuthority(role));


		return authorities;
	}


	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
	}

}

If you noticed there is one more change in the above class.

Inside the “getAuthorities” method I have added the current role to the authorities collection instead of a hardcoded value (I had hardcoded the value as “user” in the previous example).

Here is the modified “getAuthorities” method:

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {

		List<SimpleGrantedAuthority> authorities = new ArrayList<>();


		authorities.add(new SimpleGrantedAuthority(role));


		return authorities;
	}

Once you do this you need to modify your table as well (user_table) in the database.

Add a column named “role” to the table.

Insert any role you want to with the prefix “ROLE_”.

For example if you want to add an admin role , you need to insert the word “ROLE_ADMIN”.

Here is an example:

INSERT INTO USER_TABLE(id,password,role,username) values(1,'encryptedpasswordhere','ROLE_ADMIN','vijay')

STEP2: Configure access rights in configuration class.

We had already created a class named “SecurityConfiguration” in the previous example to enable authentication.

Add the below method to the above class:

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http
				.authorizeRequests()
				.antMatchers("/index.html")
				.hasAnyRole("USER","ADMIN")
				.antMatchers("/admin/admin.html")
				.hasRole("ADMIN")
				.and()
				.formLogin()

				.and()
				.logout();


	}

Notice that the above method is an overridden method.

It uses builder pattern to build the access rights.

In the above case I have created two html pages.

An index.html page which is placed directly under static folder.

An admin.html page which is placed under a folder named admin under static folder.

For the path matching “index.html” I have given the rights to both ADMIN and USER roles using the method hasAnyRole().

Notice that we are using only the word “ADMIN” and not “ROLE_ADMIN” (which is the actual value in the database)

This is a bit misleading and not sure why Spring team designed it this way.

Similarly for the path “/admin/admin.html” I have given the access only to the role “ADMIN”.

So any user who has the role value as “ROLE_ADMIN” in the table “user_table” in database can access this page. Others will get a 403 forbidden error when they login and try to access this page.

And the method formLogin() is called to provide the default login page to the user (This can be customized and a custom login form can be used )

Also I have called logout() method to implement logout.

For this to work you just need to call the path /logout when user clicks the logout link.

Here is the full SecurityConfiguration class updated from the previous example:

package com.springboot.dbauthentication;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Bean(name = "myPasswordEncoder")
	public PasswordEncoder getPasswordEncoder() {
		DelegatingPasswordEncoder delPasswordEncoder = (DelegatingPasswordEncoder) PasswordEncoderFactories
				.createDelegatingPasswordEncoder();
		BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
		delPasswordEncoder.setDefaultPasswordEncoderForMatches(bcryptPasswordEncoder);
		return delPasswordEncoder;
	}


	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http
				.authorizeRequests()
				.antMatchers("/index.html")
				.hasAnyRole("USER","ADMIN")
				.antMatchers("/admin/admin.html")
				.hasRole("ADMIN")
				.and()
				.formLogin()

				.and()
				.logout();


	}
}

That’s it!

Now let’s test the changes.

Here are the html pages :

index.html page:


Hello World!


<br>
<br>


<a href="/getMessage"> Get Message</a>

<a href="/logout">Logout</a>

admin.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Admin</title>
</head>
<body>

Hey I am Admin!

<a href="/logout">Logout</a>
</body>
</html>

I created two users in the database one with the role “ROLE_ADMIN” and another one with the role “ROLE_USER”.

Now let me try to access index.html page:

I got presented with the login form.

Now let me login with admin user:

I got logged in.

The same thing happens when I try to access using the user with the role “ROLE_USER”.

Now let me logout using the logout link shown above and try to access admin.html page using user with “ROLE_USER” role:

I was again presented with the login form and then when I tried to login , it showed me the below error page:

The admin.html page is not accessible for the user with “ROLE_USER” role.

I have not configured any error page and that is why the above default error page got shown.

Now let me try to login using admin user:

The admin page got displayed!

That’s it!

In the above example , only one role can be given to a user.

If you want to assign multiple roles to a user you can do that by creating a separate “role” table and another “users_roles” table to map the users with their roles.

Will explain that in another post.

Here is the updated code:

https://github.com/vijaysrj/spring-boot-postgresql-dbauthentication


Posted

in

by

Comments

2 responses to “How to do user authorization in Spring Boot?”

  1. Федор Жулитов Avatar
    Федор Жулитов

    It can be build, but can’t start

    2021-06-09 14:16:27.125 WARN 21560 — [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization – cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [D:\IdeaProjects\spring-boot-postgresql-dbauthentication-master\spring-boot-postgresql-dbauthentication-master\target\classes\com\springboot\dbauthentication\DbauthenticationApplication.class]; nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file – probably due to a new Java class file version that isn’t supported yet: file [D:\IdeaProjects\spring-boot-postgresql-dbauthentication-master\spring-boot-postgresql-dbauthentication-master\target\classes\com\springboot\dbauthentication\DbauthenticationApplication.class]; nested exception is java.lang.IllegalArgumentException: Unsupported class file major version 60
    2021-06-09 14:16:27.178 ERROR 21560 — [ main] o.s.boot.SpringApplication : Application run failed

    1. Vijay SRJ Avatar
      Vijay SRJ

      Which java version are you using

Leave a Reply to Vijay SRJCancel reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading