스프링 시큐리티 시리즈
- 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에 접속해도 기본 로그인 화면만 나오게 됩니다. 기본 로그인 화면이 뜨지 않게 하기 위해 초기 세팅을 합니다.
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.02.54.png)
기본 로그인 화면
메인 스프링 애플리케이션인 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입니다.
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.37.40.png)
첫 페이지
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.38.01.png)
운영자(admin)으로 로그인 한 경우
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.38.18.png)
운영자가 전용 페이지에 접근했을 때
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.38.35.png)
손님(guest)으로 로그인한 경우
![](http://yoonbumtae.com/wp-content/uploads/2019/02/스크린샷-2019-09-22-오후-5.38.56.png)
손님이 운영자 전용 페이지에 접속하려고 할 때
스프링 시큐리티 시리즈
- 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 […]