[リサーチ・メモ] spring-secueiryとVueを使用してログイン画面を作成する#2DB登録ユーザーでログインまで

## UserDetailsImplを作成する
※ユーザー情報を提供するインタフェースの実装
```
public class UserDetailsImpl implements UserDetails {
	private static final long serialVersionUID = 1L;
	private String email;
	private String password;
	private Collection<GrantedAuthority> authorities;

	public UserDetailsImpl(String email, String password, Collection<GrantedAuthority> authorities) {
		this.email = email;
		this.password = password;
		this.authorities = authorities;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return authorities;
	}

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return email;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}
}

```
| メソッド| 戻り値の設定| 内容|
|--|--|--|
| Collection<? extends GrantedAuthority> getAuthorities() | コンストラクタで設定した値 | 権限リストを返す|| String getPassword()| コンストラクタで設定した値 | パスワードを返す                             |
| String getUsername()                                | コンストラクタで設定した値 | ユーザー名を返す                             |
| boolean isAccountNonExpired()                       | 常に true とする        | アカウントの有効期限の判定                    |
| boolean isAccountNonLocked()                        | 常に true とする        | アカウントのロック状態の判定                   |
| boolean isCredentialsNonExpired()                   | 常に true とする        | 資格情報の有効期限の判定                       |
| boolean isEnabled()                                 | 常に true とする        | 有効なユーザーであるかの判定                    |

## UserDetailsServiceImplを作成する
※ユーザー情報をDBから取得するインタフェースの実装
```
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	JdbcTemplate jdbcTemplate;

	@Override
	public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
		try {
			String sql = "SELECT * FROM members WHERE email = ?";
			Map<String, Object> map = jdbcTemplate.queryForMap(sql, email);
			String password = (String) map.get("password");
			Collection<GrantedAuthority> authorities = new ArrayList<>();
			authorities.add(new SimpleGrantedAuthority((String) map.get("authority")));
			return new UserDetailsImpl(email, password, authorities);
		} catch (Exception e) {
			throw new UsernameNotFoundException("user not found.", e);
		}
	}
}
```

## Security Configを修正する
※インメモリからDB判定に変更
```
	@Autowired
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//		auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("user")
//				.password(passwordEncoder().encode("test")).roles("USER");
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
```
※認証情報を返すように設定
```
.formLogin(form -> form.loginProcessingUrl("/login")
                    .successHandler((request, response, authentication) -> {
                        Object principal = authentication.getPrincipal();
                        String authority = authentication.getAuthorities().isEmpty() ? "":authentication.getAuthorities().iterator().next().getAuthority();

                        Map<String, String> data = new HashMap<>();
                        if (principal instanceof UserDetails) {
                            UserDetails userDetails = (UserDetails) principal;
                            data.put("email", userDetails.getUsername());
                            data.put("authority", authority);
                        }

                        response.setStatus(HttpStatus.OK.value());
                        response.setContentType("application/json;charset=UTF-8");
                        new ObjectMapper().writeValue(response.getOutputStream(), data);
                    })
```

## 取得したログイン情報の権限によって遷移先を変更する
```
const login = async () => {
    try {
        const response = await axios.post(BASE_URL + '/login', {
            username: memberInfo.email,
            password: memberInfo.password,
        }, {
            headers: {
                'Content-type': 'application/x-www-form-urlencoded'
            }
        });
        if (response.status === 200) {
            console.log("Login success:", response);

            //権限で遷移先判定
            if (response.data.role === 'ADMIN') {
            //管理者ページへ遷移
            router.push('/admin')
            } else {
            //マイページへ遷移
            router.push('/myPage')
            }
        }
    } catch (error) {
        //ログイン失敗時エラー
        console.error("Login failed:", error);
    }
}
```