시큐리티로 회원가입 후 로그인은
form태그안에 버튼을 넣었기 때문에 클릭시 submit이 됨,
버튼에 타입을 지정해주지 않으면 자동 타입은 submit
form action="/auth/loginProc"에 주소추가
<form action="/auth/loginProc" method="post">
<div class="form-group">
<label for="username">username:</label> <input type="text"
class="form-control" placeholder="Enter username" name="username" id="username">
</div>
<div class="form-group">
<label for="password">password</label> <input type="password"
class="form-control" placeholder="Enter password" name="password" id="password">
</div>
<div class="form-group form-check">
<label class="form-check-label"> <input name="remember"
class="form-check-input" type="checkbox"> Remember me
</label>
</div>
<button id="btn-login" class="btn btn-primary">로그인 </button>
</form>
apiController로 회원가입은로직은 했지만,로그인 시큐리티가 확인하기 위해서 아래에
loginProcessingUrl("/auth/loginProc")
추가
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()//csrf 토큰 비활성화 (테스트시걸어두는게 좋음)
.authorizeRequests()
.antMatchers("/","/auth/**","/js/**","/css/**", "/images/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/auth/loginForm")
.loginProcessingUrl("/auth/loginProc");//스프링 시큐리티가 로그인을 가로채서 대신 로그인을 해준다.
.defaultSuccessUrl("/"); //정상적으로 요청이 완료
return http.build();
}
config안에 패키지마 "auth"만들고 auth안에 PrincipalDetail 클래스 생성
/*
*
* UserDetails 추상메서드를 들고있는데 이걸 오버라이딩 해야한다.
*
*
*스프링시큐리티가 로그인 요청을 가로채서 로그인을 진행하고 완료가 되면
*UserDetail타입의 오브젝트를스프링시큐리티의 고유한세션저장소에 저장을 해준다.
* */
public class PrincipalDetail implements UserDetails {
// 오브젝트
private User user; // 객체를 품고있는거, 콤포지션
//생성자
public PrincipalDetail(User user) {
this.user = user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
// 계정이 만료되지않았는지 리턴 (true:만료안됨)
@Override
public boolean isAccountNonExpired() {
return true;
}
// 계정이 잠겨있는지, 안잠겨있는지 리턴 (true:잠기지않음)
@Override
public boolean isAccountNonLocked() {
return true;
}
// 비밀번호가 만료되지 않았는지 리턴한다.(true:만료안됨)
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 계정활성화여부 (true:활성화)
@Override
public boolean isEnabled() {
return true;
}
// 계정이 갖고있는 권한 목록을 리턴한다.(권한이 여러개 있을 수 있어서 for문을 돌려야 하는데 현재는 한개만 )
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collectors = new ArrayList<>();
// collectors.add(new GrantedAuthority() {
// @Override
// public String getAuthority() {
// //ROLE_이건 규칙
// return "ROLE_" + user.getRole(); //ROLE_USER , ROLE_ADMIN
// }
// });
//람다식으로
collectors.add(()->{return "ROLE_" + user.getRole();});
return collectors;
}
}
시큐리티가 대신 로그인해주는데 password를 가로채기할때 해당 password가 뭘로 해쉬가 되어
회원가입이 되었는지 알아야, 로그인할 때 같은해쉬로 암호화해서 db에있는 해쉬랑 비교할 수있음
//추가해준다.
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(null).passwordEncoder(encodePWD());
}
현재 userDetailsService(null) 부분에 들어가야되는파일은 아직 만들지 않았음. 그래서 auth패키지에서 PrincipalDetailService.java 파일을 생성
findByUsername 찾는 쿼리문추가
public interface UserRepository extends JpaRepository<User, Integer>{
//네이밍쿼리
//select* from user where username = 1?
Optional<User> findByUsername(String username);
}
시큐리티를 사용할 때
✅ findByUsername 로직을 반드시 만들어줘야,
우리가 원하는 유저타입을 넣을 수 있다.
@Service
public class PrincipalDetailService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
//스프링이 로그인요청을 가로챌때, usernname,password변수 2개를 가로채는데
//password 부분처리는 알아서함.
//username이 db에 있는지만 확인하면 됨
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User principal= userRepository.findByUsername(username)
.orElseThrow(()->{
return new UsernameNotFoundException("해당사용자를 찾을 수 없습니다. " + username);
});
return new PrincipalDetail(principal); //시큐리티세션에 유저정보가 저장이 됨
}
}
User principal를 PrincipalDetail에 담아주고
PrincipalDetail을 리턴해준다.
그럼타입이 UserDetails 타입이니까..!
우리가 만든 유저오브젝트를 시큐리티에 넣어서 담아줄 수 있는 것.
public class PrincipalDetail implements UserDetails {
// 오브젝트
private User user; // 객체를 품고있는거, 콤포지션
//생성자
public PrincipalDetail(User user) {
this.user = user;
}
}
userDetailsService(null) 부분에 들어갈 로직을 만들었기 때문에 로직을 넣어주기 위해 다시
SecurityConfig.java로 가서 수정.
@RequiredArgsConstructor
public class SecurityConfig{
//생성자 주입
private PrincipalDetailService principalDetailService;
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(principalDetailService).passwordEncoder(encodePWD());
}
내가 회원가입할때 입력했던 비밀번호를 입력하면
로그인이 정상적으로 완료 !
데이터베이스에는 해쉬화되어있는거 완료♥️