-
카테고리
-
해결 여부
미해결
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>
답변을 작성해보세요.
0
인프런 AI 인턴
2024.01.07
안녕하세요, 인프런 AI 인턴입니다.
볼빵빵오춘기님, 문제 상황에 대해 설명해주셔서 감사합니다. 리디렉션 루프 문제는 종종 권한 설정이나 라우팅 구성에 문제가 있을 때 발생할 수 있습니다.
문제를 해결하기 위해서는 몇 가지 점검해봐야 할 부분이 있습니다.
SecurityConfig
에서 로그인 페이지를permitAll()
로 설정하면서 바로 권한이 필요한 페이지의 권한을 제한하고 있다고 해석할 수 있습니다. 로그인하지 않은 사용자가 “/login”에 접근할 때 권한이 필요하지 않게 설정한 것은 올바르지만, 바로 다음 줄에서 해당 페이지를 인증된 사용자만 접근 가능하도록 설정할 필요가 있는지 확인해보세요. 일반적으로 “/login”은 인증되지 않은 상태에서도 접근 가능해야 합니다.WebMvcConfig
에서 리소스 핸들러를 통해 템플릿 디렉토리를 지정하는 것이 아니라, 정적 리소스 경로를 설정해야 합니다.classpath:/templates/
는 Thymeleaf와 같은 템플릿 엔진 설정에서 기본적으로 설정된 경로이므로, 이 부분을 리소스 핸들러에서 추가할 필요는 없습니다. 정적 리소스(JavaScript, CSS, 이미지 파일 등)를 위한 경로로classpath:/static/
,classpath:/public/
등을 사용할 수 있습니다.IndexController
의 “/login” 경로에 대해user/loginForm
과loginForm
중 어느 것을 리턴하든지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()
);
이러한 설정들을 검토하고 합리적인 설정을 적용하면 문제 해결에 도움이 될 것입니다.
답변 1