@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//form Login 기능 사용
http.formLogin()
.loginPage("/login").permitAll();
//form Logout 기능 사용 로그아웃 성공시 -> "/"
http.logout()
.logoutSuccessUrl("/");
}
}
위와 같이 설정하고 login.html의 form에서 th:action="@{/login}" method="post"와 같이 설정한다면 post로 가는 /login 요청을 formLogin을 처리하는 시큐리티가 처리해준다.
🎉 장점과 효과
따로 url ="/login" post를 처리하는 핸들러를 만들 필요가 없음.
PasswordEncoder도 Bean으로 등록이 되어있다면 자동으로 사용이 된다. (하나만 있는 경우)알아서 username과 password를 가지고 로그인을 처리한다. 이 때, 데이터베이스에 저장된 정보를 참조하여 인증을 하여야 하기 때문에 데이터베이스를 조회할 수 있는 UserDetailsService를 구현해야 한다.
🔍 UserDetailService를 구현하기 전에 우선 NickName과 Email 둘 중 하나라도 입력하면 로그인 되게 구현할 것이다.
UserDetailService 구현
@Service
@RequiredArgsConstructor
public class AccountService implements UserDetailsService {
private final AccountRepository accountRepository;
@Override
public UserDetails loadUserByUsername(String emailOrNickname) throws UsernameNotFoundException {
Account account = accountRepository.findByEmail(emailOrNickname);
if(account == null){ // 이메일로 찾지 못한 경우 닉네임으로 찾는다.
account = accountRepository.findByNickname(emailOrNickname);
}
if(account == null){ // 닉네임으로도 찾지 못한다면 에러를 던짐
throw new UsernameNotFoundException(emailOrNickname);
}
// Principal 에 해당하는 객체를 리턴한다.
return new UserAccount(account);
}
}
loadUserByUsername()
상세 정보를 조회하는 메서드이며, 사용자 계정정보와 권한을 갖는 UserDetails인터페이스를 반환해야 한다.
매개변수는 로그인 시 입력한 아이디이다. 엔티티의 PK를 뜻하는 것이 아니고, 유저를 식별할 수 있는 어떠한 값을 의미한다. 스프링 시큐리티에서는 username라는 이름으로 사용한다.
로그인 form에서 아이디에 해당하는 값의 name=”username”으로 요청해야 한다.
UserDetailsService에서 return하는 객체는 UserDetails타입이어야 한다
따라서 UserDetails를 구현하는 User클래스를 상속받은 UserAccount를 리턴한다.
📣 위에서 말한 것과 같이 아이디를 입력하는 input태그의 name에는 username으로 들어가야한다. 그래야 Spring security가 인식한다!
<form class="needs-validation col-sm-6" action="#" th:action="@{/login}" method="post" novalidate>
<div class="form-group">
<label for="username">이메일 또는 닉네임</label>
<input id="username" type="text" name="username" class="form-control"
placeholder="your@email.com" aria-describedby="emailHelp" required>
<small id="emailHelp" class="form-text text-muted">
가입할 때 사용한 이메일 또는 닉네임을 입력하세요.
</small>
<small class="invalid-feedback">이메일을 입력하세요.</small>
</div>
<div class="form-group">
<label for="password">패스워드</label>
<input id="password" type="password" name="password" class="form-control"
aria-describedby="passwordHelp" required>
<small id="passwordHelp" class="form-text text-muted">
패스워드가 기억나지 않는다면, <a href="#" th:href="@{/email-login}">패스워드 없이 로그인하기</a>
</small>
<small class="invalid-feedback">패스워드를 입력하세요.</small>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="rememberMe" name="remember-me" checked>
<label class="form-check-label" for="rememberMe" aria-describedby="rememberMeHelp">로그인 유지</label>
</div>
<div class="form-group">
<button class="btn btn-success btn-block" type="submit"
aria-describedby="submitHelp">로그인</button>
<small id="submitHelp" class="form-text text-muted">
스터디올래에 처음 오신거라면 <a href="#" th:href="@{/signup}">계정을 먼저 만드세요.</a>
</small>
</div>
</form>