独自ログイン機能の実装（Config編）

実装の際にかなりハマったので、備忘録としてのまとめ

# ログイン設定のConfigクラス

WebSecurityConfgurerAdapterクラスを継承したSecurityConigクラスを作成。

ここに認証の設定などを追加していく。

クラスに@EnableWebSecurity,@Configurationアノテーションをつける。

```java
package io.post.novel.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import io.post.novel.service.UserDetailsServiceImpl;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	UserDetailsServiceImpl userDetailsService;
	

	//パスワードのハッシュ化のためのエンコーダー
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/*
	 * securityの対象外を設定
	 */
	
	@Override
	public void configure(WebSecurity web)throws Exception{
		//securityを適用しない
		
		web.ignoring()
			.antMatchers("/webjars/**")
			.antMatchers("/css/**")
			.antMatchers("/JS/**");
		
	}
	
	
	/*
	 * securityの各種設定
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception{
	
		//ログインページ不要設定
		http.authorizeRequests()
			.antMatchers("/top").permitAll() //直リンクOK
			.antMatchers("/sign_in").permitAll() //直リンクOK
			.antMatchers("/signup").permitAll() //直リンクOK
			.antMatchers("/input/check").permitAll() //直リンクOK
			.antMatchers("/signup/complete").permitAll() //直リンクOK
			.anyRequest().authenticated(); //それ以外は直リンクNG
	
		//ログイン処理	
		http.formLogin().loginProcessingUrl("/user/user_page") //ログイン処理のパス
						.loginPage("/sign_in")	//ログインページの指定
						.failureUrl("/sign_in?error")	//ログイン失敗時の遷移先
						.usernameParameter("penName")	//ログインページのユーザID
						.passwordParameter("password")	//ログインページのパスワード
						.defaultSuccessUrl("/user/user_page",true)	//成功後の遷移先
						.and()
						.logout().logoutUrl("/signout")//ログアウトのURL
						.invalidateHttpSession(true)//ログアウトのときセッション破棄
						.deleteCookies("JSESSIONID");//ログアウトの際のクッキー削除
						
		
		
		//CSRF対策を無効に設定（一時的）
		
		http.csrf().disable();
		
	}
		
		/*
		 * 認証の設定
		 */
	@Override
	protected void **configure(AuthenticationManagerBuilder auth)**throws Exception{
		
		PasswordEncoder encoder = passwordEncoder();
		
		//インメモリ認証
		/*
		auth
		.inMemoryAuthentication()
		.withUser("user")
		.password(encoder.encode("user"))
		.roles("user")
		.and()
		.withUser("admin")
		.password(encoder.encode("admin"))
		.roles("admin");
		*/
		
		//ユーザーデータで認証
		
		auth.userDetailsService(userDetailsService)
			.passwordEncoder(encoder);
		
	}
	
}
```

## コード内ポイント

### パスワードのハッシュ化のためのエンコーダー

- パスワードをハッシュ化するための**PasswordEncoderのBeanを作成**。DBに保存するパスワードをハッシュ化するときにも使用する。
- ここでは`BCryptPasswordEncoder`を利用。

### セキュリティー対象外の設定

- `configure(WebSecurity web)`メソッド内で認証の対象外のファイルを指定する。メソッドチェーンで`web.ignoring().antMatchers("/webjars/**")`を繋げていくことでその引数にしていしたファイルは認証の対象外にできる。

### セキュリティーの各種設定

- `configure(HttpSecurity http)`メソッド内に認証対象外にするページ（ユーザー登録ページなど）のURLを指定する。`http.authorizeRequests().antMatchers("/top").permitAll()`で”/top”にログインなしでアクセスできる。以下メソッドチェーンで設定の追加可能。
- `.anyRequest().authenticated();` で`.permitAll()`した以外のページはすべて認証対象となる。
- `http.formLogin()`メソッドの以下にメソッドチェーンでログインページのURLなど指定可能（コード内メモ参照）
- 認証に使うパラメータ名が**username**と**password**がデフォルト設定となっているので、`.usernameParameter("penName")`とすることで**入力フォームのname属性**を独自に指定することができる。
- `and()`以下はログアウト設定。設定しなくても**”/logout”**にアクセスするとログアウトするような機能が備わっているが、独自に設定可能（コード内メモ参照）

### 独自のログインページを利用

- `configure(AuthenticationManagerBuilder auth)`メソッド内でユーザーデータの認証を実装`auth.userDetailsService(userDetailsService)
			.passwordEncoder(encoder);`で独自に作成したuserDetailsServiceインターフェースを継承したuserDetailsServiceクラスに実装したユーザー認証を利用。
- @Autowired
	`UserDetailsServiceImpl userDetailsService;`にて依存注入しておく。