Spring

[Spring] Spring Security

ryureeru 2022. 12. 19. 20:09

Spring Security

 

  • 스프링 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크
  • 스프링 시큐리티는 필터(Filter) 흐름에 따라 처리한다는 점
  • 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 일일이 보안 관련 로직을 작성하지 않아도 된다 굿!
  • 참조 : https://mangkyu.tistory.com/76
 

[SpringBoot] Spring Security란?

대부분의 시스템에서는 회원의 관리를 하고 있고, 그에 따른 인증(Authentication)과 인가(Authorization)에 대한 처리를 해주어야 한다. Spring에서는 Spring Security라는 별도의 프레임워크에서 관련된 기능

mangkyu.tistory.com

 

 

 

1. dependency 추가 (Maven)

 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

 

 

2. 스프링 시큐리티에 대한 부분을 진행하기 위한 클래스 파일 생성

 

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	// 원하는 부분을 override 해서 사용하기
}

 

 

3. 오버라이드한 메서드들

 

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable(); // csrf 일단 작동 안하도록 설정해놈
    http.headers().frameOptions().sameOrigin();

    http.authorizeRequests()
            .antMatchers("/",
                    "/member/register",
                    "/member/email-auth",
                    "/member/find/password",
                    "/member/reset/password"
            )
            .permitAll(); // 로그인 없이 위 주소에 대해 권한 허용

    http.authorizeRequests()
            .antMatchers("/admin/**")
            .hasAuthority("ROLE_ADMIN"); // 이 권한을 가져야 위 주소에 대해 권한 허용

    http.formLogin()
            .loginPage("/member/login") // 로그인 페이지 설정
            .successHandler(userAuthenticationSuccessHandler) // 로그인 성공 시
            .failureHandler(getFailureHandler()) // 로그인 실패 시
            .permitAll();

    http.logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/member/logout")) // 로그아웃 경로
            .logoutSuccessUrl("/") // 로그아웃이 성공되면 루트로 이동하고
            .invalidateHttpSession(true); // 세션을 다 초기화 해준다

    http.exceptionHandling()
            .accessDeniedPage("/error/denied"); // 권한이 없는 사용자가 접근했을 시 이동할 경로

    super.configure(http);
}

 

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.userDetailsService(memberService) // UserDetailService를 상속하여 loadUserByUsername 메서드를 구현해준 서비스
            .passwordEncoder(getPasswordEncoder()); // 패스워드 인코더

    super.configure(auth);
}

 

@Override
public void configure(WebSecurity web) throws Exception {
    // resources 모든 접근을 허용하는 설정
    // HttpSecurity 설정한 ADMIN권한을 가진 사용자만 resources 접근가능한 설정을 무시한다
    web.ignoring().antMatchers("/favicon.ico", "/files/**"); // 무시하는 것들

    super.configure(web);
}

 

 

4. successHandler, failureHandler

 

public class UserAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    // 에러가 발생했을 때 호출되는 메서드
    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {

        String msg = "로그인에 실패하였습니다.";

        if (exception instanceof InternalAuthenticationServiceException) {
            msg = exception.getMessage();
        }

        setUseForward(true);
        setDefaultFailureUrl("/member/login?error=true");
        request.setAttribute("errorMessage", msg);

        System.out.println("로그인에 실패하였습니다.");

        super.onAuthenticationFailure(request, response, exception);
    }
}
  • failureHandler 만들기 예시
  • 만든 SecurityConfiguration 클래스에 빈 주입하기

 

 

5. UserDetailService를 상속한 서비스 클래스에 loadUserByUsername 오버로드

 

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    Optional<Member> optionalMember = memberRepository.findById(username);
    if (!optionalMember.isPresent()) {
        throw new UsernameNotFoundException("회원 정보가 존재하지 않습니다.");
    }

    Member member = optionalMember.get();

    // failureHandler로 exception throw
    if (Member.MEMBER_STATUS_REQ.equals(member.getUserStatus())) {
        throw new MemberNotEmailAuthException("이메일 활성화 이후에 로그인을 해주세요.");
    }
    if (Member.MEMBER_STATUS_STOP.equals(member.getUserStatus())) {
        throw new MemberStopUserException("정지된 회원입니다.");
    }
    if (Member.MEMBER_STATUS_WITHDRAW.equals(member.getUserStatus())) {
        throw new MemberStopUserException("탈퇴한 회원입니다.");
    }

    // 권한 부여 1
    List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
    grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
    // 권한 부여 2
    if (member.isAdminYn()) { // 관리자 true면
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
    } // ADMIN ROLE 추가
    
    return new User(member.getUserId(), member.getPassword(), grantedAuthorities); // id, pw, 권한
}

 

 

 

ㅎ ㅎ

공부가 더 필요하겠어요 ~ 

 

 

+ 넘 잘 정리된 블로그 발견

https://velog.io/@kimcno3/Spring-Security%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%ED%9A%A8%EA%B3%BC%EC%A0%81%EC%9D%B8-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%B2%98%EB%A6%AC

 

[프로젝트 2] Spring Security를 활용한 인증, 인가 처리 로직 구현

문제점 이전 프로젝트에선 세션/쿠키 인증 방식으로 로그인 기능을 구현했고, 이를 위한 로직을 직접 코드로 작성했었습니다. 그로 인해 제가 직접 구현된 로직 내에서 발생할 수 있는 에러의

velog.io

 

 

 

'Spring' 카테고리의 다른 글

[Spring] Swagger로 API 문서 자동화하기  (0) 2023.01.04
[Spring] MyBatis  (0) 2022.12.19
[Spring] JavaMailSender 이메일 전송하기  (0) 2022.12.09
[Spring] JpaAuditing  (0) 2022.10.30
[Spring] JUnit과 Mokito/단위 테스트 코드  (0) 2022.10.25