ปิดการเขียน Default Password หลังเปิดใช้งาน Spring Security

ปกติตัว Spring เองจะมี Module / Lib ที่ช่วยจัดการด้าน Security ให้ง่ายเวลาใช้เราเอา Lib ในใน pom.xml แล้ว

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>3.2.4</version>
</dependency>

ลอง build ใหม่ครับ โดยพอเมื่อใส่เข้ามาแล้ว มันจะ Default ครอบทุก API เลย โดยจะมีหน้า Login ง่ายๆ ตามนี้

แล้วเราใช้ user อะไร หละ ? ถ้าไปดูใน doc มันจะบอกว่า

  • username: user 
  • password: ระบบมันจะ Auto Generate ให้ หาจาก Log / Console แนวๆนี้ Keyword Using generated security password ...
Using generated security password: a6aad302-8a87-450a-813c-dbd65029afe8

This generated password is for development use only. Your security configuration must be updated before running your application in production.


2024-07-18T15:51:51.976+07:00  WARN 26736 --- [store-backend] [  restartedMain] .s.s.UserDetailsServiceAutoConfiguration : 
...

Using generated security password: a6aad302-8a87-450a-813c-dbd65029afe8

This generated password is for development use only. Your security configuration must be updated before running your application in production.

...
2024-07-18T15:51:51.994+07:00  INFO 26736 --- [store-backend] [  restartedMain] r$InitializeUserDetailsManagerConfigurer : Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager

แล้วทีนี้ ถ้าให้มันไป Run โผล่ลอย หรือ ไปเขียนใน Log มันดูจะไม่ดี ใน Blog นี้จะมาสรุปวิธีซ่อน Log / Console นี้ครับ

- Disable logging of the password - ปิดมันซะ

ตัว UserDetailsServiceAutoConfiguration  มันมีช่องทางให้ Debug จะมีหลาย Level แนะนำให้ OFF จะซ่อนไว้ แต่จริงๆต้องดูตาม Doc

logging.level.org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration=OFF
- Override credentials ใน Properties -ไม่ให้มัน Gen ใหม่

ยัดเอาไว้ในไฟล์ appilication.properties

spring.security.user.name=<username>
spring.security.user.password=<password>
- Override credentials ใน Code

ปรับ Code ตามนี้ได้ครับ

@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
   UserDetails user = User.withUsername("user")
                          .password(passwordEncoder.encode("P@ssW0rd"))
                          .roles("USER")
                          .build();

  UserDetails admin = User.withUsername("admin")
                          .password(passwordEncoder.encode("P@ssW0rdAdm"))
                          .roles("USER", "ADMIN")
                          .build();


  return new InMemoryUserDetailsManager(user, admin);
}
- Exclude UserDetailsServiceAutoConfiguration.class

พอไม่ Inject UserDetailsServiceAutoConfiguration พอข้อมูล Default User / Pass จะไม่ถูกสร้างขึ้นมาครับ

@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
public class MyApplication {
  public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
  }
}ja
- WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(AuthenticationManagerBuilder authManager) throws Exception {
    // This is the code you usually have to configure your authentication manager.
    // This configuration will be used by authenticationManagerBean() below.
  }

  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    // ALTHOUGH THIS SEEMS LIKE USELESS CODE,
    // IT'S REQUIRED TO PREVENT SPRING BOOT AUTO-CONFIGURATION
    return super.authenticationManagerBean();
  }
}

หลังจาก Spring Security 5.7.0-M2 ตัว WebSecurityConfigurerAdapter จะถูก deprecated ต้องมาใช้ตัว component-based security configuration ตัว Code จะประมาณนี้

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/public/**").permitAll()
                    .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
        return http.build();
    }

    //.....

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

Reference


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.