Spring Security: Convert in-memory auth to database

iamjpcbau :

I'm using in-memory auth to have my login working in spring

However, I want to change it now to persistent database

Please see code below:

JWTWebSecurityConfig

package com.sbc.cpex.security.jwt;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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 org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class JWTWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtUnAuthorizedResponseAuthenticationEntryPoint jwtUnAuthorizedResponseAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtInMemoryUserDetailsService;

    @Autowired
    private JwtTokenAuthorizationOncePerRequestFilter jwtAuthenticationTokenFilter;

    @Value("${jwt.get.token.uri}")
    private String authenticationPath;

    @Autowired
    DataSource dataSource;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

//      auth
//            .userDetailsService(jwtInMemoryUserDetailsService)
//            .passwordEncoder(passwordEncoderBean());

        auth.jdbcAuthentication().dataSource(dataSource)
        .usersByUsernameQuery("select username, password"
            + " from users where username=?")
        .passwordEncoder(passwordEncoderBean());
    }

    @Bean
    public PasswordEncoder passwordEncoderBean() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .csrf().disable()
//            .csrf().and().cors().disable()
            .exceptionHandling().authenticationEntryPoint(jwtUnAuthorizedResponseAuthenticationEntryPoint).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .anyRequest().authenticated();

       httpSecurity
            .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        httpSecurity
            .headers()
            .frameOptions().sameOrigin()  //H2 Console Needs this setting
            .cacheControl(); //disable caching
    }

    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity
            .ignoring()
            .antMatchers(
                HttpMethod.POST,
                authenticationPath
            )
            .antMatchers(HttpMethod.OPTIONS, "/**")
            .and()
            .ignoring()
            .antMatchers(
                HttpMethod.GET,
                "/" //Other Stuff You want to Ignore
            )
            .and()
            .ignoring()
            .antMatchers("/h2-console/**/**");//Should not be in Production!
    }
}

Steps I did: 1. Comment out these lines

auth
    .userDetailsService(jwtInMemoryUserDetailsService)
    .passwordEncoder(passwordEncoderBean());
  1. Add the following lines for jdbcauth
auth.jdbcAuthentication().dataSource(dataSource)
        .usersByUsernameQuery("select username, password"
            + " from users where username=?")
        .passwordEncoder(passwordEncoderBean());
  1. Create a class called DataSourceConfig
package com.sbc.cpex.security.jwt;

import javax.sql.DataSource;

import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DataSourceConfig {

    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
        dataSourceBuilder.username("test"); 
        dataSourceBuilder.password("pass"); 
        return dataSourceBuilder.build(); 
    }
}

But I'm getting this error

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'h2Console' defined in class path resource [org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.ServletRegistrationBean]: Factory method 'h2Console' threw exception; nested exception is java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.

Please enlighten me. TIA

Ananthapadmanabhan :

The stack trace itself is self explanatory :

nested exception is java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.

You need to provide the Datasource url when creating a bean of Datasource. From the stacktrace I could understand that you are using H2 . So, you could create a bean like :

@Bean
public DataSource getDataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName("org.h2.Driver");
    dataSourceBuilder.url("jdbc:h2:mem:test");
    dataSourceBuilder.username("username");
    dataSourceBuilder.password("");
    return dataSourceBuilder.build();
}

In your code, you only provided the username and password part, hence it is throwing the error.

@iamjpcbau Springboot is autoconfiguring H2 as the databse as it is found as a dependency during class path scanning. Since you have provided a Datasource bean , spring automatically takes it up for configuring H2 but the url is missing , which causes the exception that you are receiving.

Inorder to configure another database with your project, configure the database through application.properties or application.yml or manually create configuration beans so that the configuration for your corresponding database is taken up at startup instead of H2.Now, since there are no other database configured and since H2 is found on classpath , spring is configuring that by default.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=388082&siteId=1