개발공부/spring security & JWT 강의

[3강][4강] spring security 회원가입/로그인

기억지기 개발자 2023. 9. 16. 19:34

[3강]

 @Autowired
    private UserRepository userRepository;

@PostMapping({"/join"}) //securityConfig 파일 생성 후 작동안함.
    public String join(User user) {
        System.out.println(user);
        user.setRole("ROLE_USER");
        String rowPassword = user.getPassword();
        String encPassword = bCryptPasswordEncoder.encode(rowPassword);
        user.setPassword(encPassword);
        userRepository.save(user);
        return "redirect:/loginForm";
    }

위의 과정은 로그인 form에서 비밀번호가 db에 그대로 저장되지 않고, 암호화를 해서 저장할 수 있도록 하는 코드이다.

생각보다 더 간단해서 놀랐다. 

 


[4강] 

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .loginPage("/loginForm")
                ***.loginProcessingUrl("/login")
                .defaultSuccessUrl("/");
    }

***.loginProcessingUrl("/login")

"/login" 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행한다.

그래서 controller에 "/login"에 대한 정의를 따로 할 필요가 없음.

 

< PrincipalDetails 클래스의 정의 >

public class PrincipalDetails implements UserDetails {
  • 시큐리티가 "/login" 주소 요청이 오면 낚아채서 진행시킨다.
  • 로그인이 진행 완료되면 시큐리티가 시큐리티만의 자체 session을 만들어준다. (Security ContextHolder)
  • 그런데 이 세션에 접근하기 위해서는 특정 오브젝트로 접근할 수 있는데.... 
    오브젝트 타입 => Authentication 타입 객체
  • Authentication 안에 User 정보가 있어야 됨.
  • User 오브젝트타입 => UserDatails 타입 객체

Security Session -> Authentication -> UserDetails(PrincipalDetails)

 


 

< UserDetails 인터페이스 내부에 있는 함수 중 하나 >

public class PrincipalDetails implements UserDetails {
    private User user; // 콜포지션

    public PrincipalDetails(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() { //해당 user의 권한을 리턴하는 곳!!
        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collection;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }
    
    .
    .
    .(생략)

❓getAuthorities() 이란 함수는 단순히 사용자의 권한을 리턴해주는 함수인데 왜 return user.getRole()이 아닐까?

UserDetails에 있는 함수를 구현해야 하고, 거기에서 정해놓은 형식이 반환형이 Collection<? extends GrantedAuthority>  타입이기 때문에 반드시 그 규격을 따라야 한다. 따라서 return user.getRole()을 하면 반환형이 String 이기 때문에 안된다.

(collection.add(new GrantedAuthority() 를 치면 알아서 아래의 구조가 자동완성된다.) - 물론 return 값은 개발자가 직접 지정.

 


< UserDetailsService의 구현 클래스 >

// 시큐리티 설정에서 loginProcessingUrl("/login"); 에서 이 클래스가 발동
@Service
public class PrincipalDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
        User user = userRepository.findByUsername(username);
        if(user != null){
            return new PrincipalDetails(user);
        }
        return null;
    }
}
  •  시큐리티 session (내부 Authentication (내부 UserDetials))로 해당 메서드의 반환 값이 전달된다.

❗loadUserByUsername 함수를 사용할 때 주의점은?

loadUserByUsername 메서드의 인자 이름을 username으로 일치시켜야 합니다. Spring Security는 이 메서드가 호출될 때, 로그인 폼에서 입력한 아이디(username)를 자동으로 전달해 줍니다.

이렇게 두 곳의 이름이 같아야 한다는 말~~~

 

❓UserDetailsService와 UserDetails의 차이점

UserDetailsService

  • UserDetailsService 인터페이스는 Spring security가 사용자 정보를 어떻게 가져올지를 정의한 인터페이스이다.
  • 이 인터페이스를 구현한 클래스는 loadUserByUsername 메서드를 제공해야 한다.
  • 이 메서드는 사용자의 아이디(username)를 기반으로 사용자 정보를 검색하고, 이를 UserDetails 객체로 반환.

UserDetails

  • UserDetails 인터페이스는 Spring Security에서 사용자의 세부 정보를 표현하기 위한 인터페이스이다.

정리하자면, UserDetailsService는 Spring Security가 사용자 정보를 어디서 가져올지를 결정하고 UserDetails는 사용자 정보를 표현하고 저장하는 역할을 한다.