Spring Security Login 설정 문제

귀찮Lee·2022년 9월 3일
0

Error Handling Log

목록 보기
7/8
post-custom-banner

◎ Spring Security 로그인 설정

◎ 문제 상황

  1. React 리버스 프록시로 요청시, 로그인 후 로그인 정보를 클라이언트에게 주어야 하는데, 로그인 성공 후 리다이렉트시 Authentication을 null값으로 가져옴
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class SecurityController {

    @GetMapping("/success")
    public ResponseEntity returnLoginInfo(Authentication authentication){
        if (authentication == null) throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
        // BusinessLogicException 발생
        PrincipalDetails userDetails = (PrincipalDetails) authentication.getPrincipal();
        Member member = userDetails.getMember();

        MemberDto.Response response = memberMapper.memberToMemberResponseDto(member);
        return new ResponseEntity(
                new SingleResponseDto<>(response), HttpStatus.OK
        );
    }
    
}
  1. 로그인이 필요한 API에 접근하고 권한이 없다는 Response를 받고,
    로그인을 실시하면,
    로그인 성공시, 원래 처리하는 API로 응답하지 않고, 접근 권한이 막혔었던 API로 리다이렉트함

◎ 해결 방법

  • 1번 문제 해결

    • 바로 로그인 하고 난 후에 Authentication는 null이 되지만, 다시 요청했을떄는 null이 되지 않는 것을 확인함
    • 그래서 다른 API로 리다이렉트 되는 과정을 추가
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
            http.
                ...
                    .and().formLogin().loginProcessingUrl("/api/login")
                    .defaultSuccessUrl("/auth/success", true)
                    // 로그인 성공시, /auth/success로 이동
                    ...
    
            return http.build();
        }
        ...
    
    }
    @Controller
    @RequestMapping("/auth")
    public class SecurityController {
    
        @GetMapping("/success")
        public String successLogin() {
            return "redirect:/auth/info"; // 아래 API로 redirect
        }
        
        @Secured("ROLE_USER")
        @GetMapping("/info")
        public ResponseEntity returnLoginInfo(Authentication authentication){
            if (authentication == null) throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
            PrincipalDetails userDetails = (PrincipalDetails) authentication.getPrincipal();
            Member member = userDetails.getMember();
    
            MemberDto.Response response = memberMapper.memberToMemberResponseDto(member);
            return new ResponseEntity(
                    new SingleResponseDto<>(response), HttpStatus.OK
            );
        }
    
    }
  • 1번 문제 해결2

    • 갑자기 되던 문제가 다른 것들을 건드리더니 안되기 시작함 (문제 원인은 아직 발견하지 못함)
    • 따라서 로그인 후에, Client에서 한번더 요청을 보내도록 함 (해당 로그인 한 사람의 정보를 보내줌)
    • Client에서 접속할 때, 요청을 보내 현재 세션이 유지중인지 확인함
    @Controller
    @RequestMapping("/auth")
    @RequiredArgsConstructor
    public class SecurityController {
    
        private final MemberMapper memberMapper;
    
        @GetMapping("/success")
        public ResponseEntity successLogin() {
    
            return new ResponseEntity<>(
                    new Response(200, "로그인 되었습니다."), HttpStatus.OK);
        }
    
        @Secured("ROLE_USER")
        @GetMapping("/info")
        public ResponseEntity returnLoginInfo(Authentication authentication){
            if (authentication == null) throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
            PrincipalDetails userDetails = (PrincipalDetails) authentication.getPrincipal();
            Member member = userDetails.getMember();
    
            MemberDto.Response response = memberMapper.memberToMemberResponseDto(member);
            return new ResponseEntity(
                    new SingleResponseDto<>(response), HttpStatus.OK
            );
        }
    
    }
  • 2번 문제 해결

    • 다른 문제 해결을 위해 이것저것 보다가 always-use-default-target을 설정할 수 있다는 것을 알게됨
    • 따라서 always-use-default-target을 true로 설정하여 로그인 성공시 처리하는 API를 고정함
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
            http.
                ...
                    .and().formLogin().loginProcessingUrl("/api/login")
                    .defaultSuccessUrl("/auth/success", true)
                    // true : 항상 같은 url에서 처리하도록 함
                    ...
    
            return http.build();
        }
        ...
    
    }

◎ 참고자료

profile
배운 것은 기록하자! / 오류 지적은 언제나 환영!
post-custom-banner

0개의 댓글