SOLUX-완숙이

spring security+jwt 회원가입, 로그인 #2

leeeehhjj 2022. 1. 12. 18:25

2022.01.12 - [SOLUX-완숙이] - spring security+jwt 회원가입, 로그인 #1

 

spring security+jwt 회원가입, 로그인 #1

security 적용 전 회원가입 코드 1. Member 클래스 package solux.wansuki.OurNeighbor_BE.domain.Member; import lombok.*; import javax.persistence.*; import java.util.ArrayList; import java.util.Collecti..

leeeehhjj.tistory.com

 

jwt 사용하기 전에 spring security를 통한 로그인을 구현해보자.

 

1. build.gradle에 dependency를 추가

testImplementation('org.springframework.security:spring-security-test')
implementation('org.springframework.boot:spring-boot-starter-security')

2. WebSecurityConfig 클래스 생성

package solux.wansuki.OurNeighbor_BE.Security.Config;

import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers("/**").permitAll();
                //.antMatchers("/**").hasAnyRole("ADMIN","USER");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

}

- @EnableWebSecurity : Spring Security Filter Chain 을 사용한다는 것을 의미

- antMatchers.hasRole을 통해 특정 URI로 들어오는 요청에 대해 권한 인증을 요청할 수 있다

 

3. LoginDto 생성

@Getter
@NoArgsConstructor
public class LoginDto {
    private String loginId;
    private String password;

    @Builder
    public LoginDto(String loginId, String password) {
        this.loginId = loginId;
        this.password = password;
    }

    public UsernamePasswordAuthenticationToken toAuthentication() {
        return new UsernamePasswordAuthenticationToken(loginId, password);
    }
}

LoginDto 클래스에서 toAuthentication 메소드를 통해 loginId와 password를 사용하여 AuthenticationToken을 생성한다.

 

4. MemberService

 @Transactional
    public Long login(LoginDto loginDto) {
        if (memberRepository.findByLoginId(loginDto.getLoginId()).orElse(null) == null) {
            return 0l;
        }

        UsernamePasswordAuthenticationToken authenticationToken = loginDto.toAuthentication();

        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        return memberRepository.findByLoginId(loginDto.getLoginId()).get().getId();
    }

loginDto의 toAuthentication에서 만든 authenticationToken을 가지고 authenticationManagerBuilder.getObject().authenticate(authenticationToken) 을 통해 아이디와 비번이 일치하는지 검증한다.

 

5. CustomUserDetailsService 클래스

@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return memberRepository.findByLoginId(username)
                .map(this::createUserDetails)
                .orElseThrow(() -> new UsernameNotFoundException("해당 유저가 없습니다"));
    }

    private UserDetails createUserDetails(Member member) {
        return new User(member.getUsername(), member.getPassword(), member.getAuthorities());
    }
}

Member클래스(UserDetails를 구현한 클래스)

public class Member implements UserDetails {

    ...
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.roles.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    @Override
    public String getUsername() {
        return loginId;
    }

authenticationManagerBuilder.getObject().authenticate(authenticationToken) 코드를 실행하면 authenticate 안에서

retrieveUser 메소드가 실행된다. 이때 retrieveUser 안에서 loadUserByUserName을 실행하게 된다. 따라서 이 메소드를 구현해줘야 한다. 이번에는 getUserName을 실행하면 loginId가 반환되도록 설정했다. 

 

 


참고 

spring security + JWT 로그인 기능 파헤치기 - 1 (tistory.com)

 

spring security + JWT 로그인 기능 파헤치기 - 1

로그인 기능은 거의 대부분의 애플리케이션에서 기본적으로 사용됩니다. 추가로 요즘은 웹이 아닌 모바일에서도 사용 가능하다는 장점과 Stateless 한 서버 구현을 위해 JWT를 사용하는 경우를 많

wildeveloperetrain.tistory.com

SPRING SECURITY + JWT 회원가입, 로그인 기능 구현 (tistory.com)

 

SPRING SECURITY + JWT 회원가입, 로그인 기능 구현

이전에 서블릿 보안과 관련된 포스트(링크)를 작성했던 적이 있습니다. 서블릿 기반의 웹 애플리케이션에서 인증과 인가 과정을 간단하게 설명했습니다. 스프링에서는 마찬가지로 이런 인증과

webfirewood.tistory.com