유튜브에서 스프링시큐리티를 심화교육하면서 조금더 레벨업 하고자 한다.
IDE : IntelliJ
언어 : Java 8
스프링부트 버전 : 2.7.13
DB : MySQL
빌드관리 도구 : Maven
OS : iOS
참고유튜브 : 메타코딩
JWT을 이용해서 로그인을 진행해보도록 하자.
auth 패키지에 PrincipalDetails 클래스를 만든다.
UserDetails를 오버라이딩 해준 후 User 모델 클래스를 불러와준후
cmd+n 로 생성자를 만들어주고 ctrl+o로 오버라이딩 메서드들을 추가해준다.
cmd+n -> constructor 후 생성자를 만들어준다.
GrantedAuthority에 권한 설정을 위해서 user모델에 있는 RoleList에서 권한을 넣어주도록 설정하고
password와 username은 user 모델에 있는 password와 username을 리턴해주고
계정 만료, 계정 잠금 설정들은 전부 true로 변경해주어서 사용할 수 있게 만들어준다.
public class PrincipalDetails implements UserDetails {
private User user;
public PrincipalDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
user.getRoleList().forEach(r-> {
authorities.add(()->r);
});
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
auth 패키지 아래에 PrincipalDetailsService를 생성해준다.
UserDetailsService를 오버라이딩 해준다.
ctrl+o 로 loadUserByUsername 메서드를 오버라이딩 해준다.
@Service 어노테이션추가로 해당 클래스가 서비스라고 지정해주고 @RequiredArgsConstructor 로 생성자들을 주입해준다.
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
return null;
}
}
그 후 UserRepository로 이동해서 findByUsername 메서드를 작성해준다.
repository 패키지 생성 후 UserRepository 인터페이스를 생성 후 JpaRepository를 오버라이딩 해준 후
findByUsername을 만들어준다. 파라메터론 username을 받아준다.
public interface UserRepository extends JpaRepository<User,Long> {
public User findByUsername(String username);
}
다시 PrincipalDetailsService로 돌아와서 username으로 찾은 유저 정보를 PrincipalDetails로 넘겨준다.
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
return new PrincipalDetails((userEntity));
}
원래대로라면 http://localhost:portnumber/login 으로 접근을 하면 해당 서비스가 동작을 하겠지만 SecurityConfig에서
formlogin을 동작하지 않게 만들었기 때문에 실행 한 후 username과 password를 보내도 404에러가 발생한다.
securityConfig에서 추가했던 필터부분을 다 주석으로 막고
body에 username 과 password를 보내면 404 에러가 뜨는걸 확인 할 수 있다.
해당부분을 위해서 필터를 추가해주어야 하는데 jwt패키지에 JwtAuthenticationFilter 클래스 생성
UsernamePasswordAuthenticationFilter를 오버라이딩해서 @RequiredArgsConstructor로 생성자를 주입해준다.
해당 클래스에서 attemptAuthentication 메서드를 오버라이딩 해주는데 해당 메서드는 /login으로 접근을 해서 로그인 요청을 할 때
실행 되는 함수이다.
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager1;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("로그인 시도중");
return super.attemptAuthentication(request, response);
}
}
위에서 만든 필터를 SecurityConfig에 추가해주기 위해서 securityConfig로 이동해서 아래와 같이 추가해준다.
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
http
.addFilter(corsConfig.corsFilter())
.addFilter(new JwtAuthenticationFilter(authenticationManager));
}
}
그리고 securityConfig에 MyCustomDsl 필터 추가해주면 된다.
그리고 로그인 시도를 다시 진행해보면 500에러가 발생을 하지만 JwtAuthenticationFilter에서 콘솔에서 찍어본 로그인시도중이라는걸 확인할 수 있다. 즉 /login으로 접근 시도를 했을 때 해당 필터를 통과한다는걸 확인 할 수있다.
/login으로 접근을 하면 username과 password를 받아서 정상적인 로그인시도인지 PrincipalDetailsService가 실행이 되어 loadUserByUsername 함수가 실행이 된다.
그렇게 로그인이 되면 PrincipalDetails를 세션에 담아주는데 jwt를 이용해서 로그인 시도를 하는데 왜 또 세션에 유저정보를 저장하느냐 한다면 권한때문에 그렇다.
권한마다 접근할수 있는 곳이 다른데 세션에 저장하지 않으면 해당기능을 사용할 수 없기 때문에 세션에 정보를 저장한 후
jwt 토큰을 만들어서 클라이언트측으로 응답해줘서 jwt를 발급한 서버가 아니더라도 다른 서버에서 유저정보같은 요청을 받아도
jwt 토큰을 이용해서 인증을 해서 해당 사용자의 정보를 제공할 수 있게 된다.
'프로젝트 > SpringSecurity' 카테고리의 다른 글
[Spring Security] 15. JWT를 이용하기 위해 강제로그인 (1) | 2023.07.19 |
---|---|
[Spring Security] 14. JWT를 이용해 로그인전 회원가입 및 db관련 수정사항 (0) | 2023.07.18 |
[Spring Security] 12. JWT를 이용하기위한 임시토큰만들어 테스트해보기 (0) | 2023.07.12 |
[Spring Security] 11. JWT를 이용하기위한 filter 등록 테스트 (0) | 2023.07.11 |
[Spring Security] 10. JWT를 이용하기위한 security 설정 (0) | 2023.07.11 |
댓글