Open cheeseLupin opened 1 year ago
시큐리티를 사용하는 가장 큰 이유인 보안 절차를 위해, 웹에서 보내는 모든 요청이 spring security 필터를 거쳐가도록 해야 한다. (이것은 web.xml에 필터를 이용하여 구현이 가능하다.)
security-context.xml
을 <context-param>
에 추가 하기spring security
필터 생성 하기web.xml -> <context-param>
변경 전
<!-- 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</param-value>
</context-param>
web.xml -> <context-param>
변경 후
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>
스프링 시큐리티 필터 생성
스프링 시큐리티 필터 생성 시, 한글 변환 필터 하단에 생성해주어야 한글 변환 필터가 시큐리티에 적용된다.
<!-- 보안 절차를 위해 모든 요청이 spring security 필터를 거쳐가도록 하기 -->
<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>
security-context에서 시큐리티 기능에 관한 설정을 할 수 있다.
로그인
, 로그아웃
기능을 이곳에서 재설정
해주었다.필수적으로 들어가야 하는 요소
가 있는데,
패스워드 암호화
가 되어있지 않으면 로그인이 되지 않는다. (DB를 이용한 로그인 시에도 동일하다.)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:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<bean id="customUserDetailsService" class="kr.co.lookst.member.CustomUserDetailsService" />
<bean id="loginSuccess" class="kr.co.lookst.member.LoginSuccessHandler" />
<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
<constructor-arg value="" />
</bean>
<security:http auto-config="true" use-expressions="true">
<!-- <security:intercept-url pattern="/member/*" access="hasRole('ROLE_MEMBER')"/> -->
<security:intercept-url pattern="/member/login" access="permitAll"/>
<security:intercept-url pattern="/member/loginCheck" access="permitAll"/>
<security:intercept-url pattern="/member/register" access="permitAll"/>
<security:intercept-url pattern="/member/idCheck" access="permitAll"/>
<security:intercept-url pattern="/member/**" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/partner/**" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/**/write" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/seller/**" access="hasRole('seller')"/>
<security:intercept-url pattern="/admin/**" access="hasRole('admin')"/>
<security:form-login login-page="/member/login"
login-processing-url="/member/login"
username-parameter="member_id"
password-parameter="member_pw"
authentication-success-handler-ref="loginSuccess"
/>
<security:csrf disabled="false" />
<security:access-denied-handler error-page="/member/accessError" />
<security:logout logout-url="/member/logout"
logout-success-url="/" />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="bcryptPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
</beans>
1) 시큐리티 기능을 이용하기 위한, 시큐리티 bean
설정 하기
http
태그, authentication-manage
태그 등을 이용할 때
<security:http>
의 형태로 작성한다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
2) 비밀번호 인코딩/디코딩을 위한 BcryptPasswordEncoder
bean
설정 하기
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
3) DB를 이용한 시큐리티 로그인을 하기 위해 customUserDetailsService
bean
설정 하기
mybatis
를 이용한 로그인 기능을 구현하기 위해 해당 설정이 필요하다.
<bean id="customUserDetailsService" class="kr.co.lookst.member.CustomUserDetailsService" />
4) 로그인 후 권한에 따른 페이지 이동을 하기 위해 login Success
bean
설정 하기
<bean id="loginSuccess" class="kr.co.lookst.member.LoginSuccessHandler" />
5) 권한에 ROLE_
이 붙지 않아도 권한 기능을 이용하도록 grantedAuthorityDefaults
bean
설정 하기
ROLE_MEMBER
와 같이 auth 컬럼이 ROLE_
로 시작해야 권한 기능이 제대로 작동한다.member
, seller
, admin
으로 설정하였기 때문에,
그대로 사용하면 권한 기능이 작동하지 않았다.ROLE_
이 붙지 않아도 권한 기능을 이용할 수 있도록 grantedAuthorityDefaults
bean
을 설정해주었다.
<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
<constructor-arg value="" />
</bean>
6) 시큐리티 설정을 위한 http 태그 설정하기
auto-config='true'
설정 시 기본 로그인 페이지 / HTTP 기본 인증 / 로그아웃 기능 등을 제공한다.
use-expressions="true"
는 SpEL을 사용한다는 의미이다.http
태그 안에서 다양한 시큐리티 설정을 할 수 있다.
<security:http auto-config="true" use-expressions="true">
···
</security:http>
<security:http auto-config="true" use-expressions="true">
···
</security:http>
다음은 3-1, 6)에서 작성한 http 태그 안에 들어가는 코드에 관한 설명이다.
1) 각 url 접근 권한 설정
pattern
에 URL을 기입하고 access
에는 사용 가능한 권한을 기입해줄 수 있다.
권한이 없을 경우 해당 URL로 접근이 불가능하다.permitAll
: 모든 권한의 유저가 접근 가능 (비로그인 포함)
hasRole('auth')
: auth에 작성되어 있는 특정 권한을 가진 로그인 사용자만 접근 가능
hasAnyRole('auth1', 'auth2', 'auth3')
: auth에 작성되어 있는 권한들을 가진 로그인 사용자들은 모두 접근 가능
<security:intercept-url pattern="/member/login" access="permitAll"/>
<security:intercept-url pattern="/member/loginCheck" access="permitAll"/>
<security:intercept-url pattern="/member/register" access="permitAll"/>
<security:intercept-url pattern="/member/idCheck" access="permitAll"/>
<security:intercept-url pattern="/member/**" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/partner/**" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/**/write" access="hasAnyRole('member', 'seller', 'admin')"/>
<security:intercept-url pattern="/seller/**" access="hasRole('seller')"/>
<security:intercept-url pattern="/admin/**" access="hasRole('admin')"/>
2) 로그인 페이지 적용
<security:form-login login-page="/member/login"
login-processing-url="/member/login"
username-parameter="member_id"
password-parameter="member_pw"
authentication-success-handler-ref="loginSuccess"
/>
@GetMapping("/login")
public String getLogin() throws Exception {
return "member/login";
}
form action
에 기입한 url를 post
방식으로 submit
할 때,
action
에 기입한 url과 login-processing-url
을 동일하게 작성해주어야 시큐리티 로그인이 작동된다.
기존 memberController에서 이용하던 로그인 기능의 Post Mapping이라고 생각하면 된다.username-parameter="member_id"
, password-parameter="member_pw"
: 시큐리티에서는 아이디와 비밀번호를 usernamer과 password로 작성해주어야 인식을 하는데,
LookSt에서는 member_id, member_pw로 작성했기 때문에 시큐리티에서 인식할 수 있도록 파라미터를 수정해야 한다.
<bean id="loginSuccess" class="kr.co.lookst.member.LoginSuccessHandler" />
loginSuccess 에서 사용할 클래스는 kr.co.lookst.member
경로에 LoginSuccessHandler
로 클래스를 생성해주었다.
package kr.co.lookst.member;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
public class LoginSuccessHandler implements org.springframework.security.web.authentication.AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication auth) throws IOException, ServletException {
System.out.println("Login Success");
List<String> roleNames = new ArrayList<>();
auth.getAuthorities().forEach(authority -> {
roleNames.add(authority.getAuthority());
});
System.out.println("ROLE NAMES: " + roleNames);
if(roleNames.contains("admin")) {
// admin 권한을 가진 사용자가 이동할 url
response.sendRedirect("/lookst/admin/member_management");
return;
}
if(roleNames.contains("member")) {
// member 권한을 가진 사용자가 이동할 url
response.sendRedirect("/lookst");
return;
}
// 선언하지 않은 권한의 회원이 이동할 url
response.sendRedirect("/lookst");
}
}
3) csrf토큰 사용 여부 설정
<security:csrf disabled="false" />
4) 에러페이지 이동
<security:access-denied-handler error-page="/member/accessError" />
에러페이지로 사용하는 메서드
//권한이 없는 경우 노출될 에러 페이지 (403에러 대신 노출)
@GetMapping("/accessError")
public void accessDenied(Authentication auth, Model model) {
model.addAttribute("msg", "Access Denied");
}
에러페이지로 사용하는 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Access Denied Page</h1>
시큐리티 구현은
java기반
과xml기반
이 있다.gradle
과maven
두 가지 모두 가능하지만, LookSt는 maven을 사용하므로 maven에 의존성을 주입해주었다.1. 시큐리티 의존성 추가 - pom.xml
properties 추가
dependencies 추가