JDBC 驗證與授權


到目前為此,都是使用 inMemoryAuthentication 作為驗證授權的資料來源,當然,你可以採用其他的來源,在這邊先談一下基本的 JDBC 存取資料庫,最簡單的方式就是呼叫 AuthenticationManagerBuilderjdbcAuthentication,設定 DataSource、使用者資料查詢 SQL 以及角色查詢 SQL:

package cc.openhome.web;

...略

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.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=?");
    }

    ... 略

    @Bean(destroyMethod="shutdown")
    public DataSource dataSource(){
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .addScript("classpath:db.sql")
                .build();
    }

    ... 略
}

使用者資料查詢 SQL 主要必須取得名稱、密碼與是否可用三個欄位,而角色查詢必須取得名稱與角色對應兩個欄位,這麼一來 Spring Security 就能夠進行驗證與授權了,為此,你可以如下建立表格以及測試用的資料(為 db.sql 的部份內容):

CREATE TABLE t_account (
  name VARCHAR(15) NOT NULL,
  password VARCHAR(64) NOT NULL,
  enabled TINYINT NOT NULL,
  PRIMARY KEY (name)
);

CREATE TABLE t_account_role (
    name VARCHAR(15) NOT NULL,
    role VARCHAR(15) NOT NULL,
    PRIMARY KEY (name, role)
);

INSERT INTO t_account(name, password, enabled) VALUES ('admin','$2a$10$PUFa4u8d434aWitf87scE.vue580tghpCU6JdPnDXQgjK1q0Ddtgu', 1);
INSERT INTO t_account(name, password, enabled) VALUES ('caterpillar','$2a$10$yh5WJetawp2KloUtEoVzRuT4/WEeR5BhPdfRZGoAvnCtKAbFBP8Sa', 1);
INSERT INTO t_account_role (name, role) VALUES ('admin', 'ROLE_ADMIN');
INSERT INTO t_account_role (name, role) VALUES ('admin', 'ROLE_MEMBER');
INSERT INTO t_account_role (name, role) VALUES ('caterpillar', 'ROLE_MEMBER');

由於使用的 PasswordEncoder 實作為 BCryptPasswordEncoder,因此密碼資料的部份是經過 BCryptPasswordEncoderencode 方法編碼過的結果,admin 的密碼原本是 admin12345678,而 caterpillar 的密碼原本是 12345678

當然,如果是從既有專案重構而來,資料庫表格或者是驗證方式等,未必可以符合以上的設計,或者是有些情境下的驗證與授權更為複雜,這些情況下,可以透過實作 UserDetailsServiceAuthenticationProvider 來實作更有彈性的驗證與授權,這留著之後,試著在 gossip 專案上套用 Spring Security 再來說明。

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