오늘은 스프링 시큐리티 롤 기반의 접근과 권한 예제를 살펴보겠습니다. 그러나 이 글을 읽기 전에 “스프링 4 시큐리티 MVC 로그인 로그아웃 예제”에 대한 이전 글을 읽어 기본적인 스프링 4 시큐리티에 대한 지식을 습득해 주세요.
스프링 시큐리티 롤
이 글에서는 스프링 웹 애플리케이션에서 “USER”, “ADMIN”과 같은 스프링 시큐리티 롤을 어떻게 정의, 사용 및 관리하는지에 대해 논의하겠습니다. 이전 글과 마찬가지로 이 예제는 In-Memory Store 및 스프링 자바 구성 기능을 사용하여 Spring 4 MVC Security를 사용합니다. 즉, web.xml 파일을 사용하지 않고 Spring XML 구성을 작성하지 않습니다. 우리는 “In-Memory Store” 옵션을 사용하여 사용자 자격 증명을 저장하고 관리할 것입니다. 이 예제를 개발하기 위해 Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 및 Java 1.8, Maven 빌드 도구를 사용할 것입니다.
스프링 시큐리티 롤 기반의 접근과 권한 예제
- Spring STS Suite에서 “Simple Spring Web Maven” 프로젝트를 다음과 같은 세부 사항으로 생성하십시오.
프로젝트 이름 : SpringMVCSecruityMavenRolesApp2. 이전 게시물에서 사용한 pom.xml 파일을 동일하게 사용하되 다음과 같이 변경 사항을 적용하십시오.
<artifactId>SpringMVCSecruityMavenRolesApp</artifactId>
<build>
<finalName>SpringMVCSecruityMavenRolesApp</finalName>
</build>
</project>
- 이전 게시물의 모든 Java 및 JSP 파일을 사용하십시오. 여기에서는 업데이트 된 내용 또는 새로 추가된 내용에 대해서만 논의할 것입니다.
- LoginSecurityConfig.java 파일을 업데이트하여 “USER” 및 “ADMIN”과 같은 사용자 역할을 구성하십시오.
LoginSecurityConfig.java
package com.journaldev.spring.secuity.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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;
@Configuration
@EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication()
.withUser("jduser").password("jdu@123").authorities("ROLE_USER")
.and()
.withUser("jdadmin").password("jda@123").authorities("ROLE_USER","ROLE_ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/homePage").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
.antMatchers("/userPage").access("hasRole('ROLE_USER')")
.antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/loginPage")
.defaultSuccessUrl("/homePage")
.failureUrl("/loginPage?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/loginPage?logout");
}
}
코드 설명
- configureGlobal() 메소드에서 두 개의 사용자를 추가했습니다. “ROLE_USER” 역할을 갖는 사용자와 “ROLE_USER” 및 “ROLE_ADMIN” 역할을 모두 갖는 다른 사용자입니다. 이 두 번째 사용자는 관리자 사용자로 작동합니다. 이와 같이 우리는 어떤 수의 사용자와 역할을 구성할 수 있습니다.
- 응용 프로그램에서 역할을 구성하기 위해 authorities(ROLE) 또는 roles(ROLE) 메소드를 사용할 수 있습니다.
- authorities()와 roles() 메소드의 차이점 :
- authorities()는 “ROLE_USER”와 같은 완전한 역할 이름이 필요합니다.
- roles()는 “USER”와 같은 역할 이름이 필요합니다. 자동으로 이 “USER” 역할 이름에 “ROLE_” 값을 추가합니다.
- configure() 메소드에서는 필요한 액세스 역할이 있는 다른 URL을 정의했습니다.
antMatchers("/homePage")
.access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
이 코드 스니펫은 “homePage”가 USER 및 ADMIN 역할에 모두 사용 가능하도록 구성합니다.
.antMatchers("/userPage").access("hasRole('ROLE_USER')")
.antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")
이 코드 스니펫은 “userPage”가 “USER” 역할에만 접근 가능하도록 구성하고 “adminPage”가 “ADMIN” 역할에만 접근 가능하도록 구성합니다. 다른 역할이 이러한 페이지에 액세스하면 “403 액세스가 거부되었습니다.” 오류 메시지가 표시됩니다.
- 아래와 같이 새로운 URL 액세스 경로를 정의하도록 LoginController.java 컨트롤러 파일을 업데이트하십시오.
LoginController.java
package com.journaldev.spring.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class LoginController {
@RequestMapping(value = { "/"}, method = RequestMethod.GET)
public ModelAndView welcomePage() {
ModelAndView model = new ModelAndView();
model.setViewName("welcomePage");
return model;
}
@RequestMapping(value = { "/homePage"}, method = RequestMethod.GET)
public ModelAndView homePage() {
ModelAndView model = new ModelAndView();
model.setViewName("homePage");
return model;
}
@RequestMapping(value = {"/userPage"}, method = RequestMethod.GET)
public ModelAndView userPage() {
ModelAndView model = new ModelAndView();
model.setViewName("userPage");
return model;
}
@RequestMapping(value = {"/adminPage"}, method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.setViewName("adminPage");
return model;
}
@RequestMapping(value = "/loginPage", method = RequestMethod.GET)
public ModelAndView loginPage(@RequestParam(value = "error",required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid Credentials provided.");
}
if (logout != null) {
model.addObject("message", "Logged out from JournalDEV successfully.");
}
model.setViewName("loginPage");
return model;
}
}
코드 설명 이전 포스트 예제에 추가로 두 개의 새로운 URL을 추가했습니다.
-
“/userPage”는 USER 역할이 정상 사용자 활동을 액세스하고 수행하는 데 사용됩니다.
-
“/adminPage”는 ADMIN 역할이 관리자 사용자 활동을 액세스하고 수행하는 데 사용됩니다. ADMIN 역할은 “/userPage” URL에도 액세스할 수 있습니다.
-
사용자 및 관리자 역할별 활동을 제공하기 위해 homePage.jsp 파일을 업데이트했습니다.
homePage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<a href="${pageContext.request.contextPath}/userPage">JD User</a> | <a href="${pageContext.request.contextPath}/adminPage">JD Admin</a> | <a href="javascript:document.getElementById('logout').submit()">Logout</a>
<h3>Welcome to JournalDEV Tutorials</h3>
<ul>
<li>Java 8 tutorial</li>
<li>Spring tutorial</li>
<li>Gradle tutorial</li>
<li>BigData tutorial</li>
</ul>
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
여기에 상단 프레임에 세 가지 메뉴 옵션을 추가했습니다. “로그아웃”은 이전 포스트에서 설명되었습니다. 새로운 두 개의 링크는 다음과 같습니다:
- JD 사용자: “USER” 및 “ADMIN” 역할 모두에서 액세스 가능
- JD 관리자: “ADMIN” 역할에서만 액세스 가능
참고:- 실시간 애플리케이션에서는 “USER” 역할에만 “JD 사용자” 링크를 표시하고 “JD 관리자” 링크를 숨깁니다. “USER” 역할에서 액세스 가능한지 여부를 테스트하고 정확한 오류 메시지를 확인하기 위해 이 링크를 숨기지 않았습니다. 20. “ADMIN” 역할의 홈페이지로 작동하는 새로운 adminPage.jsp 파일을 추가하십시오.
adminPage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>Admin Page</h3>
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
- “USER” 역할을 위한 새로운 userPage.jsp 파일을 추가합니다.
userPage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>User Page</h3>
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
우리는 애플리케이션 개발을 완료했습니다. 이제 프로젝트의 최종 구조를 확인하고 애플리케이션을 테스트할 시간입니다.26. 최종 프로젝트 구조는 다음과 같습니다:
Spring Security Roles 예제 애플리케이션 테스트
- 스프링 STS IDE에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 “Run AS >> Run on Server” 옵션을 선택합니다. 아래에 표시된 대로 기본 응용 프로그램 환영 페이지에 액세스됩니다.
3. “Login to JournalDEV” 링크를 클릭합니다. 이제 로그인 페이지에 있습니다.
5. “USER” 역할 자격 증명으로 첫 번째로 로그인합니다. 사용자 이름: jduser 비밀번호: jdu@123
이제 3개의 메뉴 옵션인 “JD User”, “JD Admin” 및 “Logout”이 있는 응용 프로그램 홈페이지를 볼 수 있습니다. “JD User” 링크를 클릭합니다. “USER” 역할 자격 증명을 사용하여 응용 프로그램에 로그인했기 때문에 아래에 표시된 대로이 링크에 액세스 할 수 있습니다.
스프링 STS IDE에서 뒤로 가기 화살표를 사용하고 이번에는 “JD Admin” 링크를 클릭합니다. “USER” 역할 자격 증명으로 로그인했기 때문에이 링크에 액세스 할 수 없습니다. 그래서 “403 Access is denied”라는 오류 메시지를 보았습니다. 9. 이제 ADMIN 역할 자격 증명으로 로그인 한 다음 “JD Admin” 링크에 액세스 할 수 있습니다.
“Logout” 링크를 테스트하여 응용 프로그램에서 로그 아웃합니다.
{
“error”: “Upstream error…”
}