SecurityConfig 설정 후 return 페이지 무한루프 질문입니다.

24.01.06 17:02 작성 조회수 429

0

다름아니라 SecurityConfig 설정 관련 강의를 들은 후 혼자 만들어보면서 공부할려고 하는 중에 생긴 문제입니다. 해결해볼려고 몇 시간 헤매다 해결이 되지않아 질문합니다.

 

질문내용

문제가 생긴 시점에 만든 파일은

자바 파일은

  • java > 프로젝트이름 > config > SecurityConfig.java

  • java > 프로젝트이름 > config > WebMvcConfig.java

  • java > 프로젝트이름 > controller > IndexController.java

html 파일은

  • resources > templates > main > index.html (문제 생긴부분때문에 정상작동여부 확인차 main이란 디렉터리에 넣음)

     

  • resources > templates > user > loginForm.html

  • resources > templates > loginForm.html

     

(loginForm.html은 위치가 다르게 파일이름은 같지만 문제점이 생겨 똑같은 이름으로 경로만 다르게 해서 2개 만들었으며 내용부분에 다른 부분이라면 페이지에 h1태그안에 로그인1,2 이렇게 글자만 다르게해서 브라우저에서 보일 때 어디 경로에 있는 html이 뜬건지 확인하도록 하였습니다.)

 

먼저 문제가 생긴 부분이 어떤 부분인지 말하자면 SecurityConfig 에 권한 설정 후 로그인하지 않은 사용자가 권한이 있는 페이지를 요청할 경우 "/login" 페이지로 이동 시키는 부분입니다.

 

제가 회원가입 뿐만 아니라 게시판, api를 이용한 페이지 이런 부분을 만들어서 보여주고싶은데 이 페이지들이 많아지면 디렉토리로 나눠놓는것이 좋을것같아 templates 밑에 디렉토리를 나누게 되었는데요.

 

resources > templates > user > loginForm.html 을 만들어서
IndexController 에서 // 로그인 페이지 테스트2를 주석처리 후 // 로그인 페이지 테스트1를 주석해제 하고

http://localhost:8080/login 를 실행시키면 화면에

"localhost에서 리디렉션한 횟수가 너무 많습니다." 라고 떠서 Sysout에서 확인해보니 url 요청 test1 라고 계속 뜹니다.(=> 이 부분 때문에 무한루프에 빠졌다고 생각하고 있습니다.)

 

그런데

IndexController 에서 // 로그인 페이지 테스트1를 주석처리 후 // 로그인 페이지 테스트2를 주석해제 하고

http://localhost:8080/login 를 실행시키면 화면이 정상적으로 작동됩니다.

(// 로그인 페이지 테스트1// 로그인 페이지 테스트2 다른 부분은 return 부분밖에 없습니다.)

 

저는 templates 밑에 하위 디렉터리를 만들어서 작업을 계속 하고 싶은데 이 부분 어떻게 해결해야할까요??

 

코드는 아래와 같습니다.

SecurityConfig


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.configurers.CsrfConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration //
@EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터체인에 등록
public class SecurityConfig{


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http.csrf(CsrfConfigurer::disable).cors(Customizer.withDefaults());


        http.formLogin((formLogin) ->
                    formLogin.loginPage("/login").permitAll().defaultSuccessUrl("/"))
                .authorizeHttpRequests(authorize ->
                authorize
                        .requestMatchers("/login").permitAll() // 추가부분
                        .requestMatchers("/user/**").hasAnyRole("user","center","admin") // /user/** url => user, center, admin  권한이 있는 사용자만 접근 가능
                        .requestMatchers("/center/**").hasAnyRole("center","admin") // /center/** url => center, admin  권한이 있는 사용자만 접근 가능
                        .requestMatchers("/admin/**").hasAnyRole("admin") // /center/** url => admin  권한이 있는 사용자만 접근 가능
                       .anyRequest().permitAll() // 권한을 주지않은 url 이 아니면 접근 허용
        );

        //.formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/")

        //.formLogin((formLogin) ->
        //                formLogin.loginPage("/login").permitAll().defaultSuccessUrl("/")
        //        ) // 위에 권한이 접근허용이 되지않은 비회원이 해당 페이지 들어갈 경우 /login 페이지로 이동

        return http.build();
    }

}

WebMvcConfig

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry){
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/templates/")
                .setCacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES));
    }
    
}

IndexController

@Controller
public class IndexController {

    // 메인 페이지
    @GetMapping({"","/"})
    public String index(){
        return "main/index";
    }

    // 로그인 페이지 테스트1
//    @GetMapping("/login")
//    public String login(){
//        System.out.println("url 요청 test1");
//        return "user/loginForm";
//    }

    // 로그인 페이지 테스트2
    @GetMapping("/login")
    public String login(){
        System.out.println("url 요청 test2");
        return "loginForm";
    }

    // 권한 설정 Test => Test 후에 지우기
    @GetMapping("/user")
    public @ResponseBody String user(){
        return "user";
    }

    @GetMapping("/center")
    public @ResponseBody String center(){
        return "center";
    }

    @GetMapping("/admin")
    public @ResponseBody String admin(){
        return "admin";
    }

    @GetMapping("/join")
    public @ResponseBody String join(){
        return "join";
    }

    @GetMapping("/joinProc")
    public @ResponseBody String joinProc(){
        return "회원가입 완료됨";
    }


}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dreaming Animal</title>
</head>
<body>
메인 페이지
</body>
</html>

templates > user > loginForm.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>로그인</title>
</head>
<body>
    <h1>로그인 1</h1>
    <div>
        <form>
            <input type="text" name="username" placeholder="ID"><br>
            <input type="password" name="password" placeholder="password"><br>
            <button>로그인</button>
        </form>
    </div>
</body>
</html>

templates > loginForm.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>로그인</title>
</head>
<body>
    <h1>로그인 2</h1>
    <div>
        <form>
            <input type="text" name="username" placeholder="ID"><br>
            <input type="password" name="password" placeholder="password"><br>
            <button>로그인</button>
        </form>
    </div>
</body>
</html>

 

답변 1

답변을 작성해보세요.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.01.07

안녕하세요, 인프런 AI 인턴입니다.
볼빵빵오춘기님, 문제 상황에 대해 설명해주셔서 감사합니다. 리디렉션 루프 문제는 종종 권한 설정이나 라우팅 구성에 문제가 있을 때 발생할 수 있습니다.

문제를 해결하기 위해서는 몇 가지 점검해봐야 할 부분이 있습니다.

  1. SecurityConfig에서 로그인 페이지를 permitAll()로 설정하면서 바로 권한이 필요한 페이지의 권한을 제한하고 있다고 해석할 수 있습니다. 로그인하지 않은 사용자가 “/login”에 접근할 때 권한이 필요하지 않게 설정한 것은 올바르지만, 바로 다음 줄에서 해당 페이지를 인증된 사용자만 접근 가능하도록 설정할 필요가 있는지 확인해보세요. 일반적으로 “/login”은 인증되지 않은 상태에서도 접근 가능해야 합니다.

  2. WebMvcConfig에서 리소스 핸들러를 통해 템플릿 디렉토리를 지정하는 것이 아니라, 정적 리소스 경로를 설정해야 합니다. classpath:/templates/는 Thymeleaf와 같은 템플릿 엔진 설정에서 기본적으로 설정된 경로이므로, 이 부분을 리소스 핸들러에서 추가할 필요는 없습니다. 정적 리소스(JavaScript, CSS, 이미지 파일 등)를 위한 경로로 classpath:/static/, classpath:/public/ 등을 사용할 수 있습니다.

  3. IndexController의 “/login” 경로에 대해 user/loginFormloginForm 중 어느 것을 리턴하든지 SecurityConfig와 충돌이 없어야 합니다. 각 경로에 따른 뷰의 경로가 올바르게 설정되어 있는지 확인하세요.

무한 루프에 빠지는 것은 일반적으로 로그인 페이지로 리디렉션하도록 설정한 후에, 로그인 페이지 자체가 다시 인증을 요구하게 설정되어 있기 때문에 발생합니다. 그렇기 때문에 “/login” 경로는 어떤 상황에서든 권한 없이 접근할 수 있어야 합니다.

SecurityConfig 파일에서 다음과 같이 로그인 경로에 대해 permitAll()을 설정했지만, 또 다른 권한 설정이 충돌하는지 확인해보세요:

http.formLogin((formLogin) ->
    formLogin.loginPage("/login").permitAll().defaultSuccessUrl("/"))
.authorizeHttpRequests(authorize ->
    authorize
        .requestMatchers("/login").permitAll() // 여기서 모든 사용자의 접근을 허가
        .requestMatchers("/user/**").hasAnyRole("user","center","admin")
        // 나머지 경로에 대한 권한 설정
        .anyRequest().permitAll()
);

이러한 설정들을 검토하고 합리적인 설정을 적용하면 문제 해결에 도움이 될 것입니다.