inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

1927

볼빵빵오춘기

작성한 질문수 4

0

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

 

질문내용

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

자바 파일은

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 인턴입니다.
볼빵빵오춘기님, 문제 상황에 대해 설명해주셔서 감사합니다. 리디렉션 루프 문제는 종종 권한 설정이나 라우팅 구성에 문제가 있을 때 발생할 수 있습니다.

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

  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()
);

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

케이테스트 서버 운영 방법

2

52

1

강의 추천해주세요

2

29

1

수업 잘 들었습니다.

2

17

2

맥유저 입장의 고려해주세요

2

51

1