스프링 시큐리티 시리즈
- Spring Boot: 시큐리티(Security) – 1
- Spring Boot: 시큐리티(Security) – 2 – 커스텀 로그인 페이지 만들기
- Spring Boot: 시큐리티(Security) – 3 – 로그인 및 권한 정보를 DB에서 가져오기
- Spring Boot: 시큐리티(Security) – 4 – 로그인 폼을 거치지 않고 컨트롤러에서 로그인
- Spring Boot: 시큐리티(Security) – 5 – 권한별 접근 가능한 페이지를 데이터베이스에 설정하기 (동적 설정)
- Spring Boot Security OAuth2: 커스텀 로그인 페이지 구현
스프링에서 로그인, 권한별 접근 기능 등을 구현하고 싶다면 스프링 시큐리티(Spring Security)를 사용해야 합니다.
1. 처음 스타트 프로젝트 생성 시 디펜던시에서 Security를 선택합니다.
나중에 수동으로 추가할 경우에는 아래를 pom.xml
의 <dependencies>
내에 추가합니다.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
2. 프로젝트를 생성하고 서버를 가동하면 어떤 URL에 접속해도 기본 로그인 화면만 나오게 됩니다. 기본 로그인 화면이 뜨지 않게 하기 위해 초기 세팅을 합니다.
메인 스프링 애플리케이션인 SecurityApplication은 따로 변경하지 않고, SecurityConfig 클래스를 생성합니다.
package com.example.security; 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.configuration.WebSecurityConfigurerAdapter; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/**").permitAll(); } }
컨트롤러인 TestController 도 작성합니다.
package com.example.security; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; @Controller public class TestController { @RequestMapping("/") public String home(ModelAndView mav) { return "home"; } @ResponseBody @RequestMapping("/test") public String test() { return "OK"; } @ResponseBody @RequestMapping("/adminOnly") public String adminOnly() { return "Secret Page"; } }
3. 일단은 현재 연결된 데이터베이스가 없으므로 메모리상에 운영자 계정을 하나 만들고 로그인 페이지도 만들어서 운영자만 adminOnly 페이지에 접근 가능하도록 하는 예제를 만들기로 합니다.
SecurityConfig: withUser
부분은 사용자를 추가하는 부분이고 roles
는 그 이름으로 된 역할을 부여합니다. WebSecurityConfigurerAdapter를 상속받았으므로 configure
메소드를 반드시 오버라이딩 해야 합니다. 주의할 점은 암호를 인코딩하는 부분인 passwordEncoder
를 사용하지 않으면 에러를 유발합니다. ({noop}
을 쓰는 다른 방법도 있는데 여기서는 다루지 않습니다.)
package com.example.security; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/adminOnly").hasAuthority("ROLE_ADMIN") .antMatchers("/**").permitAll() // 넓은 범위의 URL을 아래에 배치한다. .anyRequest().authenticated() .and() .formLogin().defaultSuccessUrl("/") // formLogin: 다른 옵션 설정이 없는 경우 시큐리티가 제공하는 기본 로그인 form 페이지 사용 .and() .logout().logoutSuccessUrl("/"); // 로그아웃 기본 url은 (/logout) // 새로 설정하려면 .logoutUrl("url") 사용 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password(passwordEncoder().encode("1234")).roles("ADMIN") .and() .withUser("guest").password(passwordEncoder().encode("guest")).roles("GUEST"); } // passwordEncoder() 추가 @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
HttpSecurity http
를 받는 첫 번째configure
메소드는 일반적인 사항을 설정합니다.http
는 내장된 대다수의 메소드들이http
객체 자신을 반환하기 때문에 제이쿼리의 그것처럼 체이닝 하여 사용할 수 있습니다.authorizeRequests
는 특정 리퀘스트에 권한을 설정합니다.antMatchers
는 특정 URL을 지정합니다.hasAuthority
는 왼쪽의antMatchers
에 권한을 설정하는데, 여기서는"ROLE_ADMIN"
이라는 권한을 가진 자들만 접속 가능하게 한다는 뜻입니다.antMatcher
의 파라미터가"/**"
인 경우 위의"/adminOnly"
URL을 제외한 나머지 모든 URL을 지정한다는 뜻이고,permitAll
은 접근한 모든 사람(손님 포함)에게 접근을 허용하겠다는 뜻입니다..anyRequest().authenticated()
는 권한별 접속을 활성화시킨다는 의미입니다.and()
는 말 그대로 AND 조건절입니다.defaultSuccessUrl("/")
은 로그인 성공시 이동할 URL을 지정하는 곳이며 “/”를 입력한 경우 기본 페이지로 이동합니다.logoutSuccessUrl
은 로그아웃 성공 시 이동할 페이지를 지정합니다.
TestController는 변경할 부분이 없습니다. pom.xml
에 다음 부분을 추가 (주의: 버전 4가 아니라 5) 합니다. 이 예제는 뷰 렌더링 엔진으로 기본 제공되는 Thymeleaf를 사용한다고 가정합니다.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 시큐리티 유틸리티, 4가 아니라 5를 써야된다. --> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency>
뷰 페이지(Thymeleaf)를 작성합니다. 다른 설정을 하지 않았다면 src/main/resources/template/ 폴더 밑에 home.html이라는 이름으로 작성합니다.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <meta charset="UTF-8"> <title>Select Menu</title> </head> <body> <a href="test">Test Page</a> <a sec:authorize="hasRole('ADMIN')" href="adminOnly">adminOnly Page</a> <a sec:authorize="!isAuthenticated()" href="login">Login</a> <a sec:authorize="isAuthenticated()" href="logout">Logout</a> <p sec:authorize="hasRole('ADMIN')">[이 부분은 운영자(ADMIN)에게만 나타남]</p> <p sec:authorize="hasRole('GUEST')">[이 부분은 손님(GUEST)에게만 나타남]</p> <p sec:authorize="isAuthenticated()">[이 부분은 로그인한 사용자(isAuthenticated) 모두에게 나타남]<p> </body> </html>
isAuthenticated()
는 멤버가 로그인 했을 때 true
를 반환하고 !
를 붙이면 그 반대의 상황(false)에서 true
를 반환합니다(!false
이므로). hasRole('')
은 로그인한 멤버가 특정 역할을 가지고 있을 때 true
를 반환합니다.sec:authorize
는 th:if
비슷한 역할인데 시큐리티 전용이라고 생각하면 되겠습니다. /login
, /logout
은 스프링 시큐리티에서 기본으로 제공하는 로그인, 로그아웃 URL입니다.
스프링 시큐리티 시리즈
- Spring Boot: 시큐리티(Security) – 1
- Spring Boot: 시큐리티(Security) – 2 – 커스텀 로그인 페이지 만들기
- Spring Boot: 시큐리티(Security) – 3 – 로그인 및 권한 정보를 DB에서 가져오기
- Spring Boot: 시큐리티(Security) – 4 – 로그인 폼을 거치지 않고 컨트롤러에서 로그인
- Spring Boot: 시큐리티(Security) – 5 – 권한별 접근 가능한 페이지를 데이터베이스에 설정하기 (동적 설정)
- Spring Boot Security OAuth2: 커스텀 로그인 페이지 구현
4개의 댓글
eoxjfroskfl · 2021년 5월 14일 10:20 오후
[이 부분은 운영자(ADMIN)에게만 나타남]
[이 부분은 손님(GUEST)에게만 나타남]
[이 부분은 로그인한 사용자(isAuthenticated) 모두에게 나타남]
이 부분이 그냥 처음에 8080 들어가도 다 나타나고 admin 으로 로그인해도 다 나타나고 guest로 로그인해도 다 나타나는데 혹시 해결방법이 있을까요?
yoonbumtae (BGSMM) · 2021년 5월 16일 12:38 오전
안녕하세요.
security config 에서 권한 설정이 되어 있는지, 아니면 thymeleaf-extras-springsecurity5 디펜던시가 설치가 되었는지 확인해 보시기 바랍니다.
감사합니다.
Spring Boot: 시큐리티(Security) – 2 – 커스텀 로그인 페이지 만들기 - BGSMM · 2019년 6월 10일 12:00 오후
[…] 이전글에서 이어지며 Spring Boot: 시큐리티(Security) – 1 참조 […]
Spring Boot: 시큐리티(Security) - 3 - 로그인 및 권한 정보를 DB에서 가져오기 - BGSMM · 2019년 6월 10일 7:54 오후
[…] Spring Boot: 시큐리티(Security) – 1 […]