【Java・SpringBoot】Springセキュリティ③ - ログイン処理の実装

Springで、ログイン画面に入力されたID・パスワードをDBに確認し、ユーザーの権限で特定のURLへのアクセスを禁止する機能を簡単に作成しましょう〜♪
前回、ホーム画面への直リンク禁止やログイン機能の実装を行いましたので、
今回は**入力したユーザーID・パスワードを、どのDBのカラムと一致するのかを設定**し、**エラーメッセージの日本語化**も行います！

#ユーザーデータの取得
* 入力されたユーザーID、パスワードをデータベースに問い合わせする処理を追加
    * SQLを実行するため、DataSourceをAutowired
    * ユーザデータ取得用SQL文を２つ用意
        * ユーザーID、パスワード、使用可否（Enabled）を検索
        * ユーザーIDと権限を検索
        * これらのSQL文を、**usersByUsernameQuery**メソッドと**authoritiesByUsernameQuery**メソッドの引数に入れる

```java
auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(USER_SQL)
                .authoritiesByUsernameQuery(ROLE_SQL);
```
* 入力されたユーザーIDとパスワードを使って、認証処理をSpringが行ってくれる

```SecurityConfig.java
package com.example.demo;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // データソース
    @Autowired
    private DataSource dataSource;

    // ユーザーIDとパスワードを取得するSQL文
    private static final String USER_SQL = "SELECT"
            + "    user_id,"
            + "    password,"
            + "    true"
            + " FROM"
            + "    m_user"
            + " WHERE"
            + "    user_id = ?";

    // ユーザーのロールを取得するSQL文
    private static final String ROLE_SQL = "SELECT"
            + "    user_id,"
            + "    role"
            + " FROM"
            + "    m_user"
            + " WHERE"
            + "    user_id = ?";

    @Override
    public void configure(WebSecurity web) throws Exception {

        //静的リソースへのアクセスには、セキュリティを適用しない
        web.ignoring().antMatchers("/webjars/∗∗", "/css/∗∗");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // ログイン不要ページの設定
        http
            .authorizeRequests()
                .antMatchers("/webjars/**").permitAll() //webjarsへアクセス許可
                .antMatchers("/css/**").permitAll() //cssへアクセス許可
                .antMatchers("/login").permitAll() //ログインページは直リンクOK
                .antMatchers("/signup").permitAll() //ユーザー登録画面は直リンクOK
                .anyRequest().authenticated(); //それ以外は直リンク禁止

        //ログイン処理
        http
            .formLogin()
                .loginProcessingUrl("/login") //ログイン処理のパス
                .loginPage("/login") //ログインページの指定
                .failureUrl("/login") //ログイン失敗時の遷移先
                .usernameParameter("userId") //ログインページのユーザーID
                .passwordParameter("password") //ログインページのパスワード
                .defaultSuccessUrl("/home", true); //ログイン成功後の遷移先

        //CSRF対策を無効に設定（一時的）
        http.csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // ログイン処理時のユーザー情報を、DBから取得する
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(USER_SQL)
                .authoritiesByUsernameQuery(ROLE_SQL);
    }
}

```


#ログイン失敗時のメッセージを日本語にする
* messages.propertiesに以下を追加

```messages.properties
# =======================================
# ログイン失敗メッセージ
# =======================================
AbstractUserDetailsAuthenticationProvider.locked=アカウントはロックされています。
AbstractUserDetailsAuthenticationProvider.disabled=アカウントは使用できません。
AbstractUserDetailsAuthenticationProvider.expired=アカウントの有効期限が切れています。
AbstractUserDetailsAuthenticationProvider.credentialsExpired=パスワードの有効期限が切れています。
AbstractUserDetailsAuthenticationProvider.badCredentials=ログインIDまはたパスワードが間違っています。
```




#起動してログイン画面を確認！
* http://localhost:8080/login
* 何も入力せずログインボタンを押すと、エラーメッセージが日本語化されました〜^^
* SpringBootのバージョン２以降から、**パスワードの暗号化が必須**となったので、現時点では、ユーザーID・パスワードを入力してもまだログインできません。次回、パスワードの暗号化を実装していきます^^


![ja_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/53506d50-9c9a-5337-0656-2ade25f1d875.png)