Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

채채

8. 스프링 시큐리티로 로그인/로그아웃, 회원 가입 구현하기 본문

spring boot

8. 스프링 시큐리티로 로그인/로그아웃, 회원 가입 구현하기

HChaeEun 2023. 7. 19. 20:52

8.2 회원 도메인 만들기

스프링 시큐리티를 사용해 인증, 인가 기능을 구현하는 것이 목적

1. 회원 정보를 저장할 테이블을 만든다.

2. 테이블과 연결할 도메인을 만든다.

3. 테이블과 연결할 회원 엔티티를 만든다.

4. 데이터를 조회해줄 리포지터리를 만든다.

5. 스프링 시큐리티에서 사용자 정보를 가져온다.

 

// build.gradle에 스프링 시큐리티 의존성 추가
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    
    testImplementation 'org.springframework.security:spring-security-test'
}

8.2.2 엔티티 만들기

domain 패키지에 User.java 파일을 생성하고 UserDetails 클래스를 상속하는 User 클래스를 만든다.

@Table(name = "users") // table명 "users"
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 생성자
@Getter // getter 생성
@Entity // 엔티티 생성
public class User implements UserDetails { // UserDetails를 상속받아 인증 객체로 사용

    @Id // id 필드를 기본키로 지정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키 자동으로 1씩 증가
    @Column(name = "id", updatable = false)
    private Long id;

    @Column(name = "email", nullable = false, unique = true) // email이라는 not null 컬럼과 매핑, 고유한 값
    private String email;

    @Column(name = "password", nullable = false)
    private String password;

    @Builder // 빌더 패턴으로 객체 생성
    public User(String email, String password, String auth) {
        this.email = email;
        this.password = password;
    }


    @Override // 권한 반환
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(new SimpleGrantedAuthority("user"));
    }

    @Override // 사용자의 id를 반환(고유한 값)
    public String getUsername() {
        return email;
    }

    @Override // 사용자의 패스워드를 반환
    public String getPassword() {
        return password;
    }

    @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; // true -> 사용 가능
    }
}

UserDetails 클래스는 스프링 시큐리티에서 사용자의 인증 정보를 담아두는 인터페이스다. 해당 객체를 통해 인증 정보를 가져오므로 필수 오버라이드 메서드를 작성하였다.

8.2.3 리포지터리 만들기

Reposity 란?

Entity에 의해 생성된 DB에 접근하는 메서드들을 사용하기 위한 인터페이스이다. User 엔티티에 대한 리포지터리를 만들기 위해, repository 디렉터리에 UserRepository.java 파일을 다음과 같이 생성한다.

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

JPA를 이용해 리포지터리를 생성했는데, 스프링 데이터 JPA는 메서드 규칙에 맞춰 메서드를 선언하면 이름을 분석해 자동으로 쿼리를 생성해준다.

사용한 findByEmail()은 email 컬럼의 값 중 파라미터로 들어오는 값과 같은 데이터를 반환한다.

 

8.2.4 서비스 메서드 코드 작성하기

스프링 시큐리이티에서 로그인을 진행할 때 사용자 정보를 가져오는 UserDetailsService 인터페이스를 구현한다. 필수로 loadUserByUsername() 메서드를 오버라이딩해서 사용자 정보를 가져오는 로직을 작성해야한다.

@RequiredArgsConstructor
@Service
public class UserDetailService implements UserDetailsService {

    private final UserRepository userRepository;

    // 사용자 이메일로 사용자의 정보를 가져오는 메서드
    @Override
    public User loadUserByUsername(String email) {
        return userRepository.findByEmail(email)
                .orElseThrow(() -> new IllegalArgumentException((email)));
    }
}

8.3 시큐리티 설정하기

실제 인증을 처리하는 설정 파일 WebSecurityConfig.java를 config 패키지 내에 작성한다.

@RequiredArgsConstructor
@Configuration
public class WebSecurityConfig {

    private final UserDetailService userService;
	
    // (1)스프링 시큐리티 기능 비활성화
    @Bean
    public WebSecurityCustomizer configure() {
        return (web) -> web.ignoring()
                .requestMatchers(toH2Console())
                .requestMatchers("/static/**");
    }
	
    // (2)특정 HTTP 요청에 대한 웹 기반 보안 구성
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeRequests() // (3)인증, 인가 설정
                .requestMatchers("/login", "/signup", "/user").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin() // (4)폼 기반 로그인 설정
                .loginPage("/login")
                .defaultSuccessUrl("/articles")
                .and()
                .logout() // (5) 로그아웃 설정
                .logoutSuccessUrl("/login")
                .invalidateHttpSession(true)
                .and()
                .csrf().disable() // (6)csrf 비활성화
                .build();
    }
	
    // (7)인증 관리자 관련 설정
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http, BCryptPasswordEncoder bCryptPasswordEncoder, UserDetailService userDetailService) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .userDetailsService(userService) // (8)사용자 정보 서비스 설정
                .passwordEncoder(bCryptPasswordEncoder)
                .and()
                .build();
    }
	
    // (9)패스워드 인코더로 사용할 빈 등록
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

(1) 모든 곳에 인증, 인가 서비스를 적용하지 않게 하기 위함

https://sh-hyun.tistory.com/79

정적 리소스(이미지, HTML 파일)에 스프링 시큐리티가 적용되면 다음과 같이 로그인 페이지를 요청하면서 정적인 요소들을 제대로 불러오지 못한다. 따라서 ignoring() 메서드를 사용해 스프링 시큐리티의 모든 기능을 사용하지 않게 설정한다.

(2) 특정 HTTP 요청에 대해 웹 기반 보안 구성

이 메서드에서 로그인, 로그아웃, 인증/인가 관련 설정을 한다.

(3) 인증, 인가 설정

 

 


참고하면 좋은 글

https://programmer93.tistory.com/68

https://velog.io/@jybin96/Controller-Service-Repository-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C#service-%EB%9E%80

 

'spring boot' 카테고리의 다른 글

JPA의 Entity Id를 Long으로 사용하는 이유  (0) 2024.01.06
QueryDSL이란?  (0) 2023.12.07
4. 스프링 부트 3와 테스트  (0) 2023.07.12
2. 스프링 부트 3 시작하기  (0) 2023.07.12
SpringBoot 패키지 개념  (0) 2022.11.29