In the previous article we have integrated Swagger 2 with Spring Boot REST CRUD API. Now we are gonna secure the REST API with Spring Security Basic Authentication and Role Based Authorization.
Authentication vs Authorization
Authentication is the process of verifying who you are, while authorization is the process of verifying what you have access to.
Let’s Get Started
Step 1: Add Spring Security dependencies
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Step 2: Create JPA Domain Entities
Role.java
@Getter
and @Setter
annotations are used to generate getter and setter methods respectively. @Data
annotation should not be used here since we have implemented hashCode
and equals
methods.
We have used Set to define many-to-many association to User. If we use a Set, the entities have to have equals()
and hashCode()
methods.
@ManyToMany
annotation is used for specifying many-to-many relationships in Hibernate. Here, any user can have many roles and any role can have many users which leads to many-to-many associtation between the two.
package com.javachinna.model;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* The persistent class for the role database table.
*
*/
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
public static final String USER = "USER";
public static final String ADMIN = "ADMIN";
public static final String ROLE_USER = "ROLE_USER";
public static final String ROLE_ADMIN = "ROLE_ADMIN";
@Id
@Column(name = "ROLE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int roleId;
private String name;
// bi-directional many-to-many association to User
@ManyToMany(mappedBy = "roles")
private Set<UserEntity> users;
public Role(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return Objects.equals(name, ((Role) obj).getName());
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Role [name=").append(name).append("]").append("[id=").append(roleId).append("]");
return builder.toString();
}
}
UserEntity.java
package com.javachinna.model;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "USER_ID")
private Long id;
private String username;
private String password;
// bi-directional many-to-many association to Role
@ManyToMany
@JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
private Set<Role> roles;
public UserEntity(String username, String password) {
this.username = username;
this.password = password;
}
}
Step 3: Create JPA Repositories
RoleRepository.java
package com.javachinna.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.javachinna.model.Role;
public interface RoleRepository extends JpaRepository<Role, Long> {
Role findByName(String name);
}
UserRepository.java
package com.javachinna.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.javachinna.model.UserEntity;
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
UserEntity findByUsername(String userName);
}
Step 4: Implement Spring Security UserDetailsService
UserDetailsServiceImpl
implements the Spring Security UserDetailsService
interface. It overrides the loadUserByUsername
for fetching user details by username from the database. This method will be called to authenticate and load user detials including information about the user’s granted authorities. Here we are getting the user details from the MySQL database using the Spring JPA repository. Also the password for a user is stored in encrypted format using BCrypt. You can generate the Bcrypt for a password using the Online Bcrypt Generator.
UserDetailsServiceImpl.java
package com.javachinna.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javachinna.model.Role;
import com.javachinna.model.UserEntity;
import com.javachinna.repo.UserRepository;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository repo;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity user = repo.findByUsername(username);
if (user != null) {
return new User(user.getUsername(), user.getPassword(), buildSimpleGrantedAuthorities(user.getRoles()));
} else {
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
private static List<SimpleGrantedAuthority> buildSimpleGrantedAuthorities(final Set<Role> roles) {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
}
Step 5: Configure Basic Authentication
Profiles.java
This class is used to define various Spring profiles. For now, let us create a constant for basicauth profile
package com.javachinna.config;
public class Profiles {
private Profiles() {
}
public static final String BASIC_AUTH = "basicauth";
}
BasicAuthSecurityConfig.java
@Profile
annotation indicates that a component is eligible for registration when one or more specified profiles are active. Here, Basic authentication will be enabled only when the application is run with “BasicAuth” profile.
package com.javachinna.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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 org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.javachinna.model.Role;
@Profile(Profiles.BASIC_AUTH)
@Configuration
@EnableWebSecurity
public class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Disable CSRF
http.csrf().disable()
// Only admin can perform HTTP delete operation
.authorizeRequests().antMatchers(HttpMethod.DELETE).hasRole(Role.ADMIN)
// any authenticated user can perform all other operations
.antMatchers("/products/**").hasAnyRole(Role.ADMIN, Role.USER).and().httpBasic()
// Permit all other request without authentication
.and().authorizeRequests().anyRequest().permitAll()
// We don't need sessions to be created.
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public UserDetailsService userDetailsService() {
return userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
}
Step 6: Configure Swagger with Basic Authentication
SwaggerConfig.java
In order to enable Basic Authentication in Swagger-UI, we need to configure the Security Schemes and Security Contexts for Swagger as highlighted below
package com.javachinna.config;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
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.service.ApiInfo;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.BasicAuth;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
private static final String BASIC_AUTH = "basicAuth";
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.javachinna")).paths(PathSelectors.any()).build().apiInfo(apiInfo())
.securitySchemes(securitySchemes()).securityContexts(List.of(securityContext()));
}
private ApiInfo apiInfo() {
return new ApiInfo("Product REST API", "Product API to perform CRUD opertations", "1.0", "Terms of service",
new Contact("Java Chinna", "www.javachinna.com", "[email protected]"), "License of API", "API license URL", Collections.emptyList());
}
private List<SecurityScheme> securitySchemes() {
return List.of(new BasicAuth(BASIC_AUTH));
}
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(Arrays.asList(basicAuthReference())).forPaths(PathSelectors.any()).build();
}
private SecurityReference basicAuthReference() {
return new SecurityReference(BASIC_AUTH, new AuthorizationScope[0]);
}
}
Step 7: Initialize Database
SetupDataLoader.java
This class is responsible for inserting the users, roles into the db if it doesn’t exist on application startup.
package com.javachinna.config;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.javachinna.model.Role;
import com.javachinna.model.UserEntity;
import com.javachinna.repo.RoleRepository;
import com.javachinna.repo.UserRepository;
@Component
public class SetupDataLoader implements ApplicationListener<ContextRefreshedEvent> {
private boolean alreadySetup = false;
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Override
@Transactional
public void onApplicationEvent(final ContextRefreshedEvent event) {
if (alreadySetup) {
return;
}
// Create user roles
var userRole = createRoleIfNotFound(Role.ROLE_USER);
var adminRole = createRoleIfNotFound(Role.ROLE_ADMIN);
// Create users
createUserIfNotFound("user", userRole);
createUserIfNotFound("admin", adminRole);
alreadySetup = true;
}
@Transactional
private final Role createRoleIfNotFound(final String name) {
Role role = roleRepository.findByName(name);
if (role == null) {
role = new Role(name);
role = roleRepository.save(role);
}
return role;
}
@Transactional
private final UserEntity createUserIfNotFound(final String name, final Role role) {
UserEntity user = userRepository.findByUsername(name);
if (user == null) {
user = new UserEntity(name, "$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6");
user.setRoles(Set.of(role));
user = userRepository.save(user);
}
return user;
}
}
Run with BasicAuth Profile
You can run the application using mvn spring-boot:run -Dspring-boot.run.profiles=basicauth
and hit the url http://localhost:8080/swagger-ui.html in the browser and click on the product-controller
tab. All the endpoints will be secured as shown below
Authorize API
Click on the Authorize button, enter the credentials user / password and click on Authorize button as shown below
Test the Services
Create Product
Click on the Create Product endpoint and click on “Try it out” and then execute
Request
Response
Delete Product
Request
Response
Since the product can be deleted by users with “Admin” role only, we are getting HTTP Status 403 Forbidden in the response
Logout and login again with the admin credentials in the Authorize dialog and execute the delete API again. The product will be deleted.
Basic Authentication Logout
You can logout the currently authorized user in the Swagger-UI Authorize dialog as shown below and login again with a different user.
Method Level Role Based Authorization
Spring Security supports authorization semantics at the method level. For example, we can restrict the invocation of methods based on the user role.
Enable Method Security
MethodSecurityConfig.java
By using @EnableGlobalMethodSecurity
we can easily secure our methods with Java configuration. It provides AOP security on methods, some of the annotations it will enable are PreAuthorize
and PostAuthorize
.
package com.javachinna.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
Secure method with Preauthorize annotation
@PreAuthorize
annotation is used to specify a method access-control expression which will be evaluated to decide whether a method invocation is allowed or not
Annotate the updateProduct
method in ProductController
with @PreAuthorize
annotation
@Override
@PutMapping("/products/{productId}")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String updateProduct(@PathVariable(value = "productId") Long productId, @RequestBody Product product) {
In the above code, we have used the @PreAuthorize
annotation with Spring-EL expression "hasRole('ROLE_ADMIN')"
in order to restrict the invocation of the updateProduct
method by users with admin role only.
Source Code
As always, you can get the source code from the Github below
https://github.com/JavaChinna/spring-boot-rest-basic-auth
Conclusion
That’s all folks! In this article, you’ve learned how to implement basic authentication for Spring Boot RESTful services.
I hope you enjoyed this article. Thank you for reading.
Hi, I tried your tutorial and I have a problem, that I am getting a session even if I am using the following code:
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS
I am facing the following behavior:
When i give wrong username, Authentication fails as expected. But, if i get success in authentication once, all other requests after that with wrong password but correct username gets authenticated successfully….
Is it getting cached somewhere? How can i disable this feature?
Thank you for supporting.
Hi, are you facing this issue while testing the REST API in Swagger-ui / Postman OR while trying to consume the REST API ? In any case, your request authroization header should contain the base64 encoded username and password that you have provided. Maybe, after the successful authentication, the incorrect password that you are providing is not getting updated in the authorization header ? Anyhow, I’m not sure how to reproduce this issue.
Sorry, but with your code I have this error
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:250) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:90) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:95) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:141) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
No, I’ve not, except spring.datasource.password
It looks like you are running the application without specifying the “BasicAuth” profile name. Please refer “Run with BasicAuth Profile” section above for running the application.
Yes… The data created by default with…
@Transactional
private final UserEntity createUserIfNotFound(final String name, final Role role) {
UserEntity user = userRepository.findByUsername(name);
if (user == null) {
user = new UserEntity(name, “$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6”);
user.setRoles(Set.of(role));
user = userRepository.save(user);
}
return user;
}
@Override
@Transactional
public void onApplicationEvent(final ContextRefreshedEvent event) {
if (alreadySetup) {
return;
}
// Create user roles
var userRole = createRoleIfNotFound(Role.ROLE_USER);
var adminRole = createRoleIfNotFound(Role.ROLE_ADMIN);
// Create users
createUserIfNotFound(“user”, userRole);
createUserIfNotFound(“admin”, adminRole);
alreadySetup = true;
}
Understood what the issue is. It looks like you are running the application without specifying the “BasicAuth” profile name. Please refer “Run with BasicAuth Profile” section above for running the application.