만약 관리자 페이지처럼 특정 계정으로만 접근 해야하는 페이지를 만들어야 한다면 어떻게 할까?
이번 포스팅에서 다룰 Spring Security를 사용한다면 이 궁금증을 해결할 수 있다. 이제 사용법을 알아보자.
1. Dependency 추가
Spring Security를 사용하기 위해 pom.xml에 dependency 4개를 다음과 같이 추가해준다.
버전은 가급적 Spring 버전과 동일하게 하는게 좋다. 본인은 여기서 버전 문제로 상당한 시간을 날렸다.
<dependencies>
...
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
</dependencies>
2. Security 설정 파일 작성
appServlet 폴더 우클릭 -> New -> Other... 에서 Spring Bean Configuration File을 선택한다.
설정 파일 이름은 security-context.xml로 정했다.
beans, context, security를 선택하여 스키마를 자동으로 추가시킨다.
<security-context.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:s="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<s:http auto-config="true" use-expressions="true">
<s:intercept-url pattern="/login.html*" access="isAnonymous()"/>
<s:intercept-url pattern="/vip.html*" access="hasRole('ROLE_USER')"/>
<s:intercept-url pattern="/admin.html*" access="hasRole('ROLE_ADMIN')"/>
<s:access-denied-handler error-page="/"/>
</s:http>
<s:authentication-manager>
<s:authentication-provider>
<s:user-service>
<s:user name="codelove" password="1365" authorities="ROLE_USER"/>
<s:user name="kimcoder" password="1366" authorities="ROLE_USER, ROLE_ADMIN"/>
</s:user-service>
</s:authentication-provider>
</s:authentication-manager>
</beans>
사용자가 특정 url 패턴으로 요청을 하면, 여기서 먼저 인증 절차를 거친다.
먼저, security 스키마를 네임스페이스 s로 쓸 수 있게 xmins:s 로 스키마를 추가했다.
s:intercept-url의 pattern이 방금 언급한 특정 url 패턴이고, access에서는 권한을 체크한다.
권한이름(authorities)은 s:user에서 name, password와 같이 생성할 수 있으며, spring security에서 제공하는 로그인 페이지에서 name, password를 맞게 입력했을 경우 해당 권한을 획득할 수 있게 된다. 그리고 권한은 한 번에 2개 이상 가질 수도 있다.
권한을 가진 사용자는 해당 pattern에 맞는 url에 접근할 수 있게 되는 것이다.
마지막으로, s:access-denied-handler는 접근 오류(403) 페이지를 대체할 페이지를 설정할 수 있다. error-page를 "/"로 설정하여 403 page를 home page로 redirect시킨다.
※ access 설명
s:http의 use-expressions를 true로 설정해야 다음과 같이 메소드 형태로 권한을 체크할 수 있다.
- isAnonymous() : 익명일 때만 접근 허용(로그인 상태에서는 접근을 허용하지 않음)
- hasRole('role') : 해당 권한이 있다면 접근 허용
- hasAnyRole('role1', 'role2') : 하나의 권한이라도 가진다면 접근 허용
- isAuthenticated() : 이미 로그인 인증을 받은 User일 경우 접근 허용, 익명 사용자는 로그인 페이지로 이동
- isRememberMe() : 자동 로그인 대상 User일 경우 접근 허용
- isFullyAuthenticated() : 자동 로그인 없이 로그인 인증을 받은 User일 경우 접근 허용
- permitAll : 모두 접근 허용
- denyAll : 모두 접근 미허용
<servlet-context.xml>
특별히 추가된 코드는 없다.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.example.demo" />
</beans:beans>
3. web.xml에 Security 설정 파일 적용
<web.xml>
context-param의 param-value에 아까 작성한 security 설정 파일 경로를 추가했다.
그리고 security를 적용할 수 있게 모든 요청에 <filter>를 적용했다.
그리고 모든 요청은 .html로 받도록 servlet-mapping도 수정해주었다.
이 외에 특별히 추가된 부분은 없다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/appServlet/security-context.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/servlet-context.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
servlet-mapping에서 모든 요청은 .html로 받도록 했기 때문에 Controller도 수정이 필요하다.
<HomeController.java>
(RequestMapping 어노테이션으로 지정한 경로 뒤에 html을 추가)
vip.jsp, admin.jsp 에서는 사용자가 각각 vip, admin 페이지로 들어왔음을 명시만 했다.
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
@RequestMapping("/vip.html")
public String vip(Model model) {
return "vip";
}
@RequestMapping("/admin.html")
public String admin(Model model) {
return "admin";
}
}
4. 실행
demo/vip.html 또는 demo/admin.html로 요청
spring security에서 제공하는 로그인 페이지이다.
접근 권한을 인증 받아야 진행할 수 있게 필터가 정상적으로 적용된 것이며, security-context.xml에서 설정한 해당 name, password를 입력해야 통과된다.
로그인 성공(vip.jsp)
로그인 성공(admin.jsp)
로그인 실패
다음 포스팅에서는 spring security에서 제공하는 로그인 페이지가 아닌,
직접 만든 로그인 페이지를 적용해보는 시간을 가질 것이다.
'Spring Series > Spring Framework' 카테고리의 다른 글
[Spring] Mybatis (0) | 2021.01.26 |
---|---|
[Spring] Spring Security(2) - 로그인 페이지 구현 (0) | 2021.01.20 |
[Spring] JDBC 트랜잭션 (0) | 2021.01.14 |
[Spring] JdbcTemplate (0) | 2021.01.11 |
[Spring] 게시판 설계 준비과정 (0) | 2021.01.07 |
댓글