Spring Security JWT 로그인 준비

바그다드·2023년 4월 19일
0

Spring Security

목록 보기
15/17
  • 지난 포스팅까지 해서 필터를 등록하고 동작하는 것까지 확인해 보았다. 이제 jwt로그인을 위한 준비를 해보자. 먼저 로그인을 위한 준비 작업을 해주자

PrincipalDetails.java 생성

  • UserDetails역할을 할 PrincipalDetails를 생성해주자
package com.pem.jwt.config.auth;

import com.pem.jwt.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

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 authorities;
    }

    @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;
    }
}

PrincipalDetailsService.java

  • 이제 username을 받아 PrincipalDetails를 생성해줄 PrincipalDetailsService를 생성해주자
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("PrincipalDetailsService의 loadUserByUsername");
        User user = userRepository.findByUsername(username);
        return new PrincipalDetails(user);
    }
}

UserRepository 인터페이스 생성

public interface UserRepository extends JpaRepository<User, Long> {
    public User findByUsername(String username);
}
  • 사실 이렇게 설정을 하고 '/login'로 요청을 보내면 PrincipalDetails와 PrincipalDetailsService가 동작을 해야하는데 SecurityConfig에서 formLogin()메서드를 disable()로 설정하였기 때문에 위의 각 메서드가 동작하지 않는다.
  • PrincipalDetails와 rincipalDetailsService가 동작할 수 있도록 필터를 새로 생성해주자!!

JwtAuthenticationFilter.java 생성

  • config/jwt 패키지를 생성하여 그 클래스를 생성해주자
// 스프링 시큐리티에서 UsernamePasswordAuthenticationFilter가 있음
// '/login'요청을 해서 username, password를 POST로 전송하면
// UsernamePasswordAuthenticationFilter가 동작함
// 그런데 현재는 '/login'이 작동하지 않기 때문에 필터를 새로 등록해줘야함
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final AuthenticationManager authenticationManager;

    // '/login'요청을 하면 로그인 시도를 위해서 실행되는 함수
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println("JwtAuthenticationFilter : 로그인 시도중");

        return super.attemptAuthentication(request, response);
    }
}
  • 이제 이 필터를 등록해주자. 이게 작동을 한다면 "JwtAuthenticationFilter : 로그인 시도중"이라는 출력문이 콘솔에 찍힐 것이다.

SecurityConfig.java 수정

  • MyCustomDsl부분에 필터를 추가해주자
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
        @Override
        public void configure(HttpSecurity http) throws Exception {
        	// AuthenticationManager 생성
            AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
            http
                    .addFilter(corsConfig.corsFilter())
                    // 추가
                    // 얘는 AuthenticationManager라는 객체를 인자로 받음
                    .addFilter(new JwtAuthenticationFilter(authenticationManager));
        }
    }
  • 이제 '/login'으로 요청을 보내보면 아래 필터가 동작하는 것을 확인할 수 있다.

  • 이제
  1. username, password를 받아서
  2. 정상인지 로그인을 시도해본다. authenticationManager로 로그인을 시도하면 PrincipalDetailsService의 loadUserByUsername()가 실행되고
  3. PrincipalDetails를 세션에 담고 (권한 관리를 위해서)
  4. JWT토큰을 만들어서 응답해주면 된다.
profile
꾸준히 하자!

0개의 댓글