오늘은 Spring Security 로그인 예제에 대해 배우게 될 것입니다. 이 게시물을 읽기 전에, 기본 지식을 얻기 위해 이전 게시물인 “Spring 4 Security 소개”를 참고하십시오.
Spring Security 로그인 로그아웃 예제
이 게시물에서는 In-Memory 옵션을 사용하여 로그인 및 로그아웃 기능을 제공하기 위해 Spring 4 MVC Security 웹 애플리케이션을 개발할 것입니다. 이 예제는 web.xml과 Spring XML 구성(이전 스타일)을 사용하지 않고 Spring Java Config와 Spring Annotations을 사용합니다. Spring 3.x Security 모듈에 익숙하지 않은 경우, 먼저 다음 게시물을 참고하여 Spring Security 레시피를 경험해보십시오.
- 인메모리, UserDetailsService 및 JDBC 인증을 사용한 Spring MVC Security 예제
- DAO, JDBC, In-Memory 인증을 사용한 서블릿 웹 애플리케이션의 Spring Security
Spring 4 Security 모듈은 다음과 같은 옵션을 지원하여 사용자 자격 증명을 저장하고 관리합니다:
- In-Memory 저장소
- 관계형 데이터베이스(RDBMS)
- No SQL 데이터 저장소
- LDAP
이 예제에서는 “In-Memory Store” 옵션을 사용할 것입니다. 다른 옵션에 대해서는 이후에 논의할 예정입니다. 이 예제를 개발하기 위해 Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 with Java 1.8 및 Maven 빌드 도구를 사용할 것입니다.
Spring Security 로그인 예제
Spring 4 보안 기능을 사용하여 로그인 및 로그아웃 로직을 개발할 예정입니다. 이 응용 프로그램의 주요 목표는 “web.xml”을 사용하지 않고 Spring XML Beans 구성에 한 줄도 작성하지 않고 응용 프로그램을 개발하는 것입니다. 이것은 Spring Java Config 기능과 Spring Annotations을 사용할 것을 의미합니다. 다음과 같은 기능을 갖춘 이 응용 프로그램을 개발할 것입니다:
- 환영 페이지
- 로그인 페이지
- 홈 페이지
- 로그아웃 기능
이 Spring 4 보안 간단한 로그인 예제를 개발하고 탐색하기 위해 다음 단계를 따라주시기 바랍니다.
- 다음 세부 정보로 Spring STS Suite에서 “Simple Spring Web Maven” 프로젝트를 생성합니다.
Project Name : SpringMVCSecruityMavenApp
- pom.xml을 다음 내용으로 업데이트합니다.
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>SpringMVCSecruityMavenApp</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<properties>
<java.version>1.8</java.version>
<spring.version>4.0.2.RELEASE</spring.version>
<spring.security.version>4.0.2.RELEASE</spring.security.version>
<servlet.api.version>3.1.0</servlet.api.version>
<jsp.api.version>2.2</jsp.api.version>
<jstl.version>1.2</jstl.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.api.version}</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
</dependencies>
<build>
<finalName>SpringMVCSecruityMavenApp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
참고:- “failOnMissingWebXml” 플래그에 대해 알지 못하는 경우, 이 게시물 끝에서 이 요소 사용에 대한 이해를 얻기 위해 읽어보십시오.- 첫째, Spring의 @Controller 주석을 사용하여 Login Controller를 개발합니다.
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 = "/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;
}
}
코드 설명:- “LoginController”에서 세 가지 메소드를 정의하여 세 가지 다른 종류의 클라이언트 요청을 처리합니다.
- welcomePage()는 “/” URI를 사용하는 모든 클라이언트 요청을 처리합니다.
- homePage()는 “/homePage” URI를 사용하는 모든 클라이언트 요청을 처리합니다.
- loginPage()는 “/loginPage” URI를 사용하는 모든 클라이언트 요청을 처리합니다.
- loginPage()에서는 오류 및 로그아웃 메시지를 처리하는 데 주의합니다.
- 그런 다음 Spring 4 Security API를 사용하여 로그인 및 로그아웃 보안 기능을 제공하기 위해 “LoginSecurityConfig” 클래스를 개발합니다.
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("journaldev")
.password("jd@123")
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
.and()
.formLogin().loginPage("/loginPage")
.defaultSuccessUrl("/homePage")
.failureUrl("/loginPage?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/loginPage?logout");
}
}
코드 설명:- “LoginSecurityConfig”에서는 사용자 자격 증명을 저장하고 관리하며 로그인 및 로그아웃 보안 기능을 처리하기 위해 두 가지 메소드를 정의합니다.
- @EnableWebSecurity 주석은 웹 애플리케이션에서 웹 보안을 활성화하기 위해 사용됩니다.
- @EnableWebMVCSecurity 어노테이션은 Spring MVC 기반 웹 애플리케이션에서 웹 보안을 활성화하는 데 사용됩니다.
참고: @EnableWebSecurity = @EnableWebMVCSecurity + 추가 기능. 이래서 @EnableWebMVCSecurity 어노테이션은 Spring 4.x Framework에서 사용되지 않습니다. “LoginSecurityConfig” 클래스 또는 Spring Security를 구성하는 데 사용되는 다른 클래스는 “WebSecurityConfigurerAdapter” 클래스를 상속하거나 관련 인터페이스를 구현해야 합니다. - configureGlobal() 메서드는 사용자 자격 증명을 저장하고 관리하는 데 사용됩니다.
- configureGlobal() 메서드에서 authorities() 메서드를 사용하여 “ROLE_USER”와 같은 애플리케이션 역할을 정의할 수 있습니다. roles() 메서드도 동일한 용도로 사용할 수 있습니다.
- authorities()와 roles() 메서드의 차이점:
- authorities()는 “ROLE_USER”와 같은 완전한 역할 이름이 필요합니다. roles()는 “USER”와 같은 역할 이름만 필요합니다. 자동으로 “ROLE_” 값이 이 “USER” 역할 이름에 추가됩니다. 참고: 이후 게시물에서 “USER”, “ADMIN”과 같은 역할을 나타내는 예제를 개발할 것입니다.
- 로그인 및 로그아웃 보안을 처리하기 위한 중요한 메서드는 configure(HttpSecurity http)입니다.
- 다음 코드 스니펫은 “/homePage”로의 무단 액세스를 방지하기 위해 사용됩니다. 이 페이지에 직접 액세스하려고 하면 자동으로 “/loginPage” 페이지로 리디렉션됩니다.
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
만약 access(“hasRole(‘ROLE_USER’)”) 메소드 호출을 제거하면, 우리는 응용 프로그램에 로그인하지 않고도 이 페이지에 접근할 수 있습니다.13. 우리는 formLogin()과 logout() 메소드를 사용하여 로그인 및 로그아웃 기능을 구성했습니다.
- Spring MVC 구성 활성화
LoginApplicationConfig.java
package com.journaldev.spring.secuity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@EnableWebMvc
@Configuration
@ComponentScan({ "com.journaldev.spring.*" })
@Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
코드 설명:- “LoginApplicationConfig” 클래스를 사용하여 Spring MVC View Resolvers를 정의하여 “web.xml” 파일을 작성하지 않도록 합니다.
- @EnableWebMvc 어노테이션은 Spring 프레임워크에서 Spring 웹 MVC 애플리케이션 기능을 활성화하는 데 사용됩니다.
- @Import 어노테이션은 이 클래스에 Spring Security 구성 클래스를 가져오는 데 사용됩니다.
- @ComponentScan 어노테이션은 지정된 패키지에서 컴포넌트 스캔을 수행하는 데 사용됩니다. 이는 Spring XML 구성의 “context:component-scan“과 동일합니다.
- Spring Security 초기화
package com.journaldev.spring.secuity.config.core;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
“SpringSecurityInitializer”는 DelegatingFilterProxy
를 등록하여 springSecurityFilterChain을 사용합니다. 이는 Filters 구성을 web.xml 파일에 작성하지 않도록 합니다. – Spring MVC 애플리케이션 초기화
“SpringMVCWebAppInitializer” 클래스는 주석 기반 구성에서 web.xml 파일 없이 “DispatcherServlet”을 초기화하는 데 사용됩니다. SpringMVCWebAppInitializer.java
package com.journaldev.spring.secuity.config.core;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.journaldev.spring.secuity.config.LoginApplicationConfig;
public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { LoginApplicationConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
참고:-
- 우리가 애플리케이션에 접근할 때, 기본적으로 SpringMVCWebAppInitializer의 getServletMappings()은 루트 URL인 “/”에 접근할 수 있도록 허용합니다. 우리는 다른 URL로 전달하기 위해 이를 재정의할 수 있습니다.
- 스프링 또는 Pivotal 팀은 이 문제를 해결하기 위해 어노테이션을 도입하여 이 정도의 자바 코드를 피할 수 있도록 노력하고 있습니다. 이 내용은 https://jira.spring.io/browse/SPR-10359에서 확인할 수 있습니다.
- welcomePage.jsp 파일을 개발하세요.
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
- loginPage.jsp 파일을 개발하세요.
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<html>
<body onload='document.loginForm.username.focus();'>
<h3>JournalDEV Tutorials</h3>
<c:if test="${not empty error}"><div>${error}</div></c:if>
<c:if test="${not empty message}"><div>${message}</div></c:if>
<form name='login' action="<c:url value='/loginPage' />" method='POST'>
<table>
<tr>
<td>UserName:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
- homepage.jsp 파일을 개발하세요.
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<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>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
Spring Security MVC 로그인 로그아웃 예제 실행하기
이 Spring 웹 애플리케이션을 실행하기 위해서는 Spring 4와 Java 8 환경을 지원하는 Servlet 3.1.0 컨테이너를 사용하는 웹 컨테이너가 필요합니다.
- Spring STS Suite에서 Spring TC Server에 배포하고 실행하세요.
- 다음과 같이 자동으로 우리의 애플리케이션 환영 페이지 URL에 액세스합니다.
– “JournalDEV에 로그인” 링크를 클릭하여 로그인 페이지에 액세스합니다.
– 이제 잘못된 로그인 세부 정보를 제공하고 “로그인” 버튼을 클릭합니다.
여기에서 이 오류 메시지를 관찰할 수 있습니다. “유효하지 않은 자격 증명이 제공되었습니다.” – 이제 “LoginSecurityConfig” 클래스에 구성된 올바른 로그인 세부 정보를 제공합니다.
애플리케이션에 성공적으로 로그인한 후에는 “로그아웃” 링크와 함께 애플리케이션 홈페이지를 볼 수 있습니다. – “로그아웃” 링크를 클릭하여 애플리케이션에서 로그아웃합니다.
여기에서 우리는 애플리케이션에서 성공적으로 로그아웃되어 다시 로그인 페이지로 리디렉션되었음을 관찰할 수 있습니다. 이 로그인 페이지에 일부 로그아웃 성공 메시지를 관찰할 수 있습니다.
참고: 이 예제를 관찰하면 우리는 web.xml 파일을 사용하지 않고 있습니다. 웹 애플리케이션인 경우 Maven은 웹.xml 파일을 찾고, 애플리케이션에서 찾지 못할 경우 일부 오류를 발생시킵니다. Maven 관련 문제를 피하기 위해 pom.xml 파일에 “
Source:
https://www.digitalocean.com/community/tutorials/spring-4-security-mvc-login-logout-example