Hi everyone,
We will be talking about how to authorization management with Spring Security. We will learn how to use basic Spring Security Framework and Swagger configuration.
What is Swagger?
Simply, an important purpose of Swagger is to provide an interface for Rest Api. You will see Swagger Interface instance on the bottom this article.
Firstly we will create a Spring Maven project with Intellij Idea or other IDEs. I suggest that you check out this tutorial.(HERE)
What is Maven?
Maven is a project addiction management tool. Maven provides such as:
- Making the build process easier
- Providing a stable build system
- Providing quality project information
- Providing rules for developing best practice
- Facilitate the transition to new features
We will use pom.xml file with Maven.
What is pom.xml( Project Object Model ) file?
A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details used by Maven to build the project.
Secondly we will add all dependencies in pom.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.caglartelef</groupId>
<artifactId>springsecurity</artifactId>
<version>0.0.1</version>
<name>springsecurity</name>
<description>Spring Security project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security Dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Lombok Dependency -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Security Test Dependency -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
<scope>compile</scope>
</dependency>
<!-- Spring Actuator Dependency for Healtcheck -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
We can keep our configs to “application.yaml” or “application.properties” file which is under the path “src/main/java/…/resources”.
spring:
application:
name: Spring Security Api
management:
endpoints:
web:
exposure:
include: '*'
base-path: /_monitoring
health:
defaults:
enabled: true
api:
authorization:
users:
caglartelef:
password: "{noop}caglartelef"
config:
timeout: false
roles:
- ROLE_ADMIN
rabiayurdakultelef:
password: "{noop}rabiayurdakultelef"
config:
timeout: false
roles:
- ROLE_ADMIN
bahadirtelef:
password: "{noop}bahadirtelef"
config:
timeout: true
roles:
- ROLE_SECADMIN
We add a new class that named is “ConfigProperties.java” which under the path “src/main/java/…/properties”.
package com.caglartelef.springsecurity.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashMap;
import java.util.Map;
@ConfigurationProperties(prefix = "api.authorization")/** Get authorization infos in application.yaml.*/
public class ApplicationProperties {
private Map<String, User> users = new HashMap<>();
public Map<String, User> getUsers() {
return users;
}
public void setUsers(Map<String, User> users) {
this.users = users;
}
/**
* User class
* */
public static class User {
private String password;
private UserConfig config;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserConfig getConfig() {
return config;
}
public void setConfig(UserConfig config) {
this.config = config;
}
}
/**
* User config class
* */
public static class UserConfig {
private boolean timeout;
private String[] roles;
public String[] getRoles() {
return roles;
}
public void setRoles(String[] roles) {
this.roles = roles;
}
public boolean isTimeout() {
return timeout;
}
public void setTimeout(boolean timeout) {
this.timeout = timeout;
}
}
}
We add a new package that named is “Configuration” under the path “src/main/java/…/configuration” and then we create a new class that named is “ConfigurationService.java” in the “Configuration” package.
package com.caglartelef.springsecurity.config;
import com.caglartelef.springsecurity.properties.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Component
public class ConfigurationService {
@Autowired
private ApplicationProperties properties;
/**
* This method provide Authenticated user class.
* */
public ApplicationProperties.User getCurrentUser() {
String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
return properties.getUsers().get(currentUsername);
}
/**
* This method provide Authenticated user name.
* */
public String getCurrentUserName() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
}
How to set up Swagger configuration. It is here and very simple.
package com.caglartelef.springsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* Swagger configuration
* */
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.caglartelef"))
.paths(PathSelectors.any())
.build();
}
We add a new class that is named “SecurityConfiguration.java” which is in the “Configuration” package. The class provides authorization for all users and requests.
package com.caglartelef.springsecurity.config;
import com.caglartelef.springsecurity.properties.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import java.util.Map;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ApplicationProperties properties;
/**
* This method checks the access information of users.
* */
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/admin/login/**").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/api/secAdmin/login/**").hasRole("SECADMIN")
.antMatchers(HttpMethod.GET, "/_monitoring/health/**").permitAll()
.anyRequest().denyAll()
.and()
.csrf().disable()
.formLogin().disable();
}
/**
* This method provide ignore to swagger configuration.
* */
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**");
}
/**
* This method allows users to login the system.
* */
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> builder = auth.inMemoryAuthentication();
Map<String, ApplicationProperties.User> users = properties.getUsers();
users.forEach((username, user) -> {
builder.withUser(username).password(user.getPassword()).authorities(user.getConfig().getRoles());
});
}
}
Lastly, we add a new package that is named Controller. We create a new class that is named ApiController in the Controller Package.
package com.caglartelef.springsecurity.controller;
import com.caglartelef.springsecurity.config.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/api")
public class ApiController {
@Autowired
private ConfigurationService configurationService;
/**
* This method provide to login for admin users.
* */
@GetMapping(value = "/admin/login")
public String adminLogin(){
System.out.println(configurationService.getCurrentUserName());
return configurationService.getCurrentUserName();
}
/**
* This method provide to login for secondary admin users.
* */
@GetMapping(value = "/secAdmin/login")
public String secAdminLogin(){
System.out.println(configurationService.getCurrentUserName());
return configurationService.getCurrentUserName();
}
}
We have finished a Spring Security Project.
You can run the project and then open the link (http://localhost:8080/swagger-ui.html).
When you see the login screen, you should press the cancel button. The Swagger page should open. You will see all controllers and end points. You can try to login in the system with user info in the application.yaml file.
Project source code is here. GİTHUB
Thank you for reading my article. Have a nice day!