Security 設置


如果想在〈DataSource 設置〉的 toy 加上 Spring Security 對每個頁面進行防護呢?這可以在 build.gradle 中加入 Security 的 Starter:

implementation('org.springframework.boot:spring-boot-starter-security')

Spring Boot 只要有 Spring Security 相對應的程式庫存在,就會自動啟用頁面防護,預設的使用者名稱為 user,密碼為隨機產生,在啟動專案時,可以於日誌訊息中看到:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

2018-12-10 09:04:27.667  INFO 14284 --- [           main] 
...略
2018-12-10 09:04:29.153  INFO 14284 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 

Using generated security password: 90a63497-e39c-45b7-a5f8-d916b26fd9f9

當然,你可以自行設置使用者名稱與密碼,這可以在 application.properties 中設定:

spring.security.user.name=caterpillar
spring.security.user.password=12345678

如果想〈套用 jdbcAuthentication〉呢?這就需要寫設定檔了,例如,直接寫在標註了 @SpringBootApplication 的主類別上:

package cc.openhome.toy;

...略

@SpringBootApplication(
    scanBasePackages={
        "cc.openhome.controller",
        "cc.openhome.model"
    }
)
public class ToyApplication {
    @Bean
    public WebSecurityConfigurerAdapter webSecurityConfig(DataSource dataSource) {
          return new WebSecurityConfigurerAdapter() {
              @Override
              protected void configure(AuthenticationManagerBuilder builder) throws Exception {
                  builder.jdbcAuthentication()
                         .passwordEncoder(new BCryptPasswordEncoder())
                         .dataSource(dataSource)
                         .usersByUsernameQuery("select name, password, enabled from t_account where name=?")
                         .authoritiesByUsernameQuery("select name, role from t_account_role where name=?");
              }
          };
    }

    public static void main(String[] args) {
        SpringApplication.run(ToyApplication.class, args);
    }
}

這樣就可以使用資料庫中相對應的名稱、密碼與角色來登入了,如果要進一步設置防護頁面:

package cc.openhome.toy;

...略

@SpringBootApplication(
    scanBasePackages={
        "cc.openhome.controller",
        "cc.openhome.model"
    }
)
public class ToyApplication {
    @Bean
    public WebSecurityConfigurerAdapter webSecurityConfig(DataSource dataSource) {
          return new WebSecurityConfigurerAdapter() {
              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.authorizeRequests()
                      .antMatchers("/user/**").hasRole("MEMBER")
                      .and()
                      .formLogin();
              }

              @Override
              protected void configure(AuthenticationManagerBuilder builder) throws Exception {
                  builder.jdbcAuthentication()
                         .passwordEncoder(new BCryptPasswordEncoder())
                         .dataSource(dataSource)
                         .usersByUsernameQuery("select name, password, enabled from t_account where name=?")
                         .authoritiesByUsernameQuery("select name, role from t_account_role where name=?");

              }
          };
    }

    public static void main(String[] args) {
        SpringApplication.run(ToyApplication.class, args);
    }
}

只要能找到 WebSecurityConfigurerAdapter,Spring Boot 就會套用其中的設定;隨著應用程式逐漸複雜,也許你會想要將一些設定,移出至其他的設定檔案之中:

package cc.openhome.toy;

...略

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
            .antMatchers("/user/**").hasRole("MEMBER")
            .and()
            .formLogin();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.jdbcAuthentication()
               .passwordEncoder(new BCryptPasswordEncoder())
               .dataSource(dataSource)
               .usersByUsernameQuery("select name, password, enabled from t_account where name=?")
               .authoritiesByUsernameQuery("select name, role from t_account_role where name=?");

    }   
}

你只要在 @SpringBootApplication 時,記得掃描設定檔所在套件就可以了:

package cc.openhome.toy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(
    scanBasePackages={
        "cc.openhome.controller",
        "cc.openhome.model",
        "cc.openhome.toy"
    }
)
public class ToyApplication {
    public static void main(String[] args) {
        SpringApplication.run(ToyApplication.class, args);
    }
}

你可以在 toy 中找到以上的範例專案。