스프링

[스프링 ]security

easy-6 2024. 11. 29. 16:37

1. 스프링 security이란?

‘springSecurity’는  인증, 권한 관리 그리고 데이터 보호 기능을 포함하여 웹 개발 과정에서 필수적인 사용자 관리 기능을 구현하는데 도움을 주는 Spring의 프레임워크 중 하나이다. 

이를 통해 spring은 개발자들이 보안 관련 기능을 효율적이고 신속하게 구현할 수 있도록 도와준다.

예시로 기존 jsp를 이용했다면, 개발자가 모든 보안에 관련된 코드를 직접 작성해야했지만, 

security 라이브러리를 이용하면 직접 작성하지 않아도 된다.

 

*아래는  Servlet 컨테이너에서 요청(Request)이 처리되고 응답(Response)이 반환되기까지의 과정이다. tomcat > filter > intercepter > aop > controller (요청 순서) 
< tomcat < filter< intercepter < aop< controller (응답 순서)

 

이때, security는 dispatcherServlet  내부에 존재 하지 않고, filter쪽에 따라서 외부에 존재한다.

 

 

그림1(전체적인 구조)
그림2(프로젝트에서Handler구조)

 

2. 스프링 security 세팅

전체적인 security 세팅 순서 

0) pom.xml에서 버전을 업그레이드 시켜야한다. 

소스코드를 통해서 기존의 내용과 달라진 여러 특징을 알 수 있다.

 

0-1)  properties 태그 안에서  release를 4.3.4로 업그레이드 , security를 추가 

0-2)  <!-- Spring Securtiy -->주석에 해당하는 부분 추가 

0-3)    <plugin>

            <configuration>

             </configuration>안에 존재하는

<source>태그 부분과 <target>부분을 1.8로 변환 

 

	
    // properties의 상단에서 build까지 해당 소스를 붙여넣으면 된다. 
    <properties>
		<java-version>1.8</java-version>
		<org.springframework-version>4.3.4.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
		<spring.security.version>3.2.10.RELEASE</spring.security.version> <!-- 추가해야함 -->
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<!-- 수정 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.2</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
		 <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <!-- mysql -->		
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.32</version>
		</dependency>	
				 		
		<!-- DB MyBatis 연결시 필요 -->
		<!-- MyBatis 3.4.1 --> 
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> 
		<dependency> 
			<groupId>org.mybatis</groupId> 
			<artifactId>mybatis</artifactId> 
			<version>3.4.1</version> 
		</dependency> 
		<!-- MyBatis-Spring --> 
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> 
		<dependency> 
			<groupId>org.mybatis</groupId> 
			<artifactId>mybatis-spring</artifactId> 
			<version>1.3.0</version> 
		</dependency>  
		<!-- Spring-jdbc --> 
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> 
		<dependency> 
			<groupId>org.springframework</groupId> 
			<artifactId>spring-jdbc</artifactId> 
			<version>${org.springframework-version}</version> 
		</dependency> 
		<!-- Spring-test --> 
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> 
		<dependency> 
			<groupId>org.springframework</groupId> 
			<artifactId>spring-test</artifactId> 
			<version>${org.springframework-version}</version> 
		</dependency> 
		<!-- Common-dbcp --> 
		<dependency> 
			<groupId>commons-dbcp</groupId> 
			<artifactId>commons-dbcp</artifactId> 
			<version>1.4</version> 
		</dependency>
		
	
		        
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

 

0-4)  pom.xml 수정 후 maven install을 실행 

그림1(pom.xml 수정 후 maven install)

 

0-5) maven update를 통해 최종적으로 버전 및 security를 추가한다.

그림2(Maven update)

 

 

 

1)   service 패키지 안에 handler를 먼저 생성

그림3(handler 생성)

여기서 각각의 핸들러는 의미를 가지고 있다. 

 

1-1)  UserAuthenticationService의 특징  

  ○ id가 일치하는 user 정보를 DB에서 가져올 수 있다 .

  ○ 조회된 정보를 담을 수 있어야 함  

// id가 일치하는 user 정보를 DB에서 가져옴
// 조회된 정보를 담을 수 있어야함
// UserDetails는 Spring Security에서 사용자의 정보를 담는 인터페이스이다.

@Override
	public UserDetails /*UserVO와 동일*/loadUserByUsername(String username) throws UsernameNotFoundException {
		// Mapper에 존재하는 해당 쿼리의 resultType="java.util.Map"이고 , 
		// sqlSession에서 selectOne의 타입은 Map<String, Object>타입을 가지므로 , 
        // sqlSession.selectOne 메소드를 사용한다.
        // 해당 키는 mapper에서 생성된 쿼리의 결과를 통해 DB에 담긴 컬럼 값을 가져온다. 
		Map<String,Object> user = sqlSession.selectOne("edu.studySpringSecurity.mapper.userMapper.selectOneById", username);
		String userid_map = (String)user.get("userid");
		String passwd_map = (String)user.get("passwd");
		int enabled_map = (Integer)user.get("enabled");
		boolean enabled = false;
		if(enabled_map == 1) {
			enabled = true;
			System.out.println("활성화된 아이디가 존재합니다.");
		}else {
			enabled = false;
			System.out.println("활성화된 아이디가 존재합니다.");
		}
/*
    List<GrantedAuthority> authorities = new ArrayList<>();
    Spring Security에서 사용자의 **권한(roles 또는 authorities)**을 저장하기 위한 리스트.
    **권한(Authority)**이란 사용자가 시스템 내에서 특정 작업을 수행할 수 있는
    권리 또는 **역할(Role)**을 의미.
 */
/*
 Role (역할):
    예: ROLE_ADMIN,ROLE_MANAGER: 관리자 권한으로 시스템 내 모든 작업 가능.
    ROLE_USER: 일반 사용자로 기본 기능만 사용 가능.
 */
		List<GrantedAuthority> authorities = new ArrayList<>();

		// 반환된 값들을 UserVO 생성 및 생성자 호출하여 vo 변수에 변수 담기 
		// security에게 반환할 유저 객체를 생성
		UserVO vo = new UserVO(userid_map,passwd_map,enabled,
				true,true,true,authorities,(String)user.get("authority") );
		return vo;
        /*
            해당 메소드의 타입은 UserDetails인데,vo의 타입이 UserVO여도 가능한 이유 
            security에서 UserDetails는 User의 정보를 담는 인터페이스이다. 
            
            UserVO는 User클래스를 상속 받고 User클래스가 UserDetails의 구현 클래스
            따라서 return vo를 사용해도 오류가 발생하지 않는다.
         */
	}

 

1-2) UserDeniedHandler의 특징 

  ○  springSecurity에서 사용자가 권한이 없는 경로에 접근했을 때 호출되는 AccessDeniedHandler의 구현체이다.

  ○  UserDetails >> SpringSecurity에서 사용자의 정보를 담는 인터페이스

package edu.studySpringSecurity.service;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

public class UserDeniedHandler implements AccessDeniedHandler{

/* authority 값이 일치하지 않은 경로(권한이 없는 경로 )접근시 호출
즉 security-context.xml에서 패턴에 맞게 세팅한 값이 아닌
다른 값이 들어올 경우 해당 메소드가 발생함
*/
/*
*** 예시와 함께 부연 설명
security-context.xml에서 
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
 패턴 생성시  /admin/이라는 경로에 'ROLE_ADMIN'의 값을 가진게 아닌 
'ROLE_USER'의 값을 가진 유저가 접근하면 
현재 클래스의 메소드가 실행되며, 경로는 메인페이지로 이동된다. 
또한 콘솔창에는 "값이 일치하지 않은 경로(권한이 없음)"문자열이 보여지게 된다. 
*/
	 
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException, ServletException {
		System.out.println("값이 일치하지 않은 경로(권한이 없음)");
		response.sendRedirect(request.getContextPath());
	}
}

 

1-3)  UserLoginFailHandler

  ○  UserAuthenticationService를 통해서 넘어간 값이 일치하지 않을 때 , 로그인 실패를 나타내는 handler

package edu.studySpringSecurity.service;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

public class UserLoginFailHandler implements AuthenticationFailureHandler{

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
		// 로그인 실패시 호출 
		System.out.println("로그인 실패");
		// 절대 경로 설정 
		response.sendRedirect(request.getContextPath() + "/login.do");
	}

}

 해당 코드는 로그인이 실패했다면 response.sendRedirect(request.getContextPath()+"/login.do");를 이용해서 ,   로그인 페이지로 보내게끔 해놓았다. 

 

 

 

 

1-4)  UserLoginSuccessHandler

  ○  UserAuthenticationService를 통해서 넘어간 값이 일치할 때, 로그인 성공을 나타내는 handler,

package edu.studySpringSecurity.service;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

public class UserLoginSuccessHandler implements AuthenticationSuccessHandler{

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		// 로그인 성공했을 때 
		System.out.println("로그인 성공");
		response.sendRedirect(request.getContextPath()+"/");
	/*
	 	response.sendRedirect(request.getContextPath()); 
	 	>> http://localhost:8080/controller 형태로 전달 되는데 
        여기서 브라우저가 알아서 /를 붙여서 home 화면을 보여준다. 
	 */
	}

}

위의 코드는 response.sendRedirect(request.getContextPath()+"/");를 통해서 메인페이지로 이동하게 해놓았다.

 

 

 

 

2)  url 패턴 생성

security-context.xml에서 아래의 3가지 순서로 패턴을 만들어야함 

우선 spring 폴더 하위에 security 폴더를 생성 후 하위에 security-context.xml을 생성한다. 

security-context.xml 페이지에서  아래의 패턴을 생성해야한다.

 

(1) 비회원

<!-- 메인페이지의 경우에는 비회원도 볼 수 있게 메인페이지를 의미하는 "/"에는 모두 접근할 수 있게 패턴 생성-->
<security:intercept-url pattern="/" access="permitAll" />

위의 코드를 통해서 pattern이 "/"(홈페이지)인 경우에는 모든 사용자가 접근할 수 있게 설정하였다.

예시로 서버의 path가 /controller일 경우에

http://localhost:8080/controller/의 값을 가지는 url(메인페이지)에는 모든 유저가 허용할 수 있게 설정되어있다.


(2) 일반

<!-- user의 경로로 오는 내용은 user와 admin 둘 다 가능 -->
<!-- 패턴   >> security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/-->
<!-- /user/로 시작하는 url은 'ROLE_USER','ROLE_ADMIN'의 권한을 가진 유저만 허용한다는 의미 -->
<security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>

위의 코드를 통해서 pattern이 user인 경우에는 관리자( 'ROLE_ADMIN' )와 일반 유저( 'ROLE_USER')만 접근할 수 있게 

access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" 코드를 이용하였다.

예시로 서버의 path가 /controller일 경우에

http://localhost:8080/controller/user/의 값을 가지는 url에는 회원들만 허용할 수 있게 설정되어있다.

 


(3) 관리자 

<!-- admin의 경로로 오는 내용은 admin의 권한을 가진 유저만 가능 -->
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>

위의 코드를 통해서 pattern이 admin인 경우에는 관리자( 'ROLE_ADMIN' 만 접근할 수 있게 

access="hasAnyRole('ROLE_ADMIN')" 코드를 이용하였다.

예시로 서버의 path가 /controller일 경우에

http://localhost:8080/controller/admin/의 값을 가지는 url에는 회원 중에서 관리자만 이용할 수 있게 설정되어있다.

 

 

3) url 패턴 생성 후 security 작업 

spring 폴더 하위에 security 폴더를 생성 후 하위에 security-context.xml을 생성한다. 

 

3-1) 위에서 작업한 handler를 bean으로 지정한다. 

<!-- 로그인 성공 핸들러 -->
<bean id="userLoginSuccessHandler"
 class= "edu.studySpringSecurity.service.UserLoginSuccessHandler"/>
<!-- 로그인 실패 핸들러 -->
<bean id="userLoginFailureHandler" 
 class="edu.studySpringSecurity.service.UserLoginFailHandler"/>
<!-- 잘못된 경로로 접근했을 때 핸들러 -->
<bean id="userDeniedHandler"
 class="edu.studySpringSecurity.service.UserDeniedHandler"/>
<!-- 로그인 확인 핸들러 -->
<bean id="userService"
 class="edu.studySpringSecurity.service.UserAuthenticationService" >
<!-- 
"해당 핸들러에서 sqlSession.selectOne() 메소드를 사용하기 때문에, 
생성자를 통해 sqlSession을 주입받도록 선언."
 -->
    <constructor-arg name="sqlSession" ref="sqlSession" />
</bean>
<!-- 비밀번호 비교할 암호화 객체 선언 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> 
<!-- 
로그인 버튼 security에서 어떤 userAuthenticationService를 사용할 지와 반환된 User 객체에서 어떤 비밀번호 암호화를 사용하여 비교 할 것인지에 대한 정보를 설정 영역 
-->	
<security:authentication-manager>
	<!-- userVO 반환 객체 참조  -->
	<security:authentication-provider user-service-ref="userService">  
		<security:password-encoder ref="passwordEncoder" />
	</security:authentication-provider>
</security:authentication-manager>

 

3-2)  스프링 시큐리티(Spring Security)에 포함된 <security:form-login> 태그를 활용하여 로그인 기능을 구현해야함

<security:form-login  login-page="/login.do" 
  login-processing-url="/loginOk.do"
  authentication-success-handler-ref="userLoginSuccessHandler" 
  authentication-failure-handler-ref="userLoginFailureHandler"
  username-parameter="userid" password-parameter="passwd"

  />

여기서 "userid" 와 "passwd"는 DB에 저장된 정보가 아닌 login페이지에서 저장된 name을 의미한다. 

즉 login 페이지에서 넘어오는 파라미터를 의미한다.

 

3-3)  로그아웃 설정

<!-- 로그아웃 설정 -->
<security:logout logout-url="/logout.do" logout-success-url="/login.do"
invalidate-session="true" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"/>

spring에서는 로그아웃을 자동으로 시켜주기 때문에 해당 코드를 작성하면 더이상 신경쓸 내용이 없이 로그아웃이 된다. 

 

 

3-4) 로그인 했으나, 경로 접근 권한이 없을시 호출 객체 설정 

<!-- 로그인은 했으나 경로 접근 권한 없을시 호출 객체를 설정  -->
<security:access-denied-handler ref="userDeniedHandler"/>

위에서 나왔던 내용처럼 userDeniedHandler를 통해서 /admin/에 user가 들어온 경우, /user/에 비회원이 들어온 경우 메인 페이지로 보낼 수 있다. 

 

📗 최종 정리된 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-3.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 제외하고자 하는 url pattern -->
	<!-- 브라우저가 읽어들여야하는 자원들에 대해서 security를 적용하지 않겠다는 의미 --> 
	<security:http pattern="/resources/**" security="none"/>
	
	<security:http auto-config="true" use-expressions="true" create-session="never">
		<security:intercept-url pattern="/" access="permitAll" />
		<!-- user의 경로로 오는 내용은 user와 admin 둘 다 가능 -->
		<!-- 패턴   >> security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/-->
		<!-- /user/로 시작하는 url은 'ROLE_USER','ROLE_ADMIN'의 권한을 가진 유저만 허용한다는 의미 -->
		<security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
		
		<!-- admin의 경로로 오는 내용은 admin의 권한을 가진 유저만 가능 -->
		<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
		
		
		<security:form-login  login-page="/login.do" 
							  login-processing-url="/loginOk.do"
							  authentication-success-handler-ref="userLoginSuccessHandler" 
							  authentication-failure-handler-ref="userLoginFailureHandler"
							  username-parameter="userid" password-parameter="passwd"
							  
							  />
		  <!-- 로그아웃 설정 -->
		  <security:logout logout-url="/logout.do" logout-success-url="/login.do"
		  invalidate-session="true" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"/>
		  <!-- 로그인은 했으나 경로 접근 권한 없을시 호출 객체를 설정  -->
		  <security:access-denied-handler ref="userDeniedHandler"/>
	</security:http>
	<!-- 로그인 성공 핸들러 -->
	<bean id="userLoginSuccessHandler"
			class= "edu.studySpringSecurity.service.UserLoginSuccessHandler"/>
	<!-- 로그인 실패 핸들러 -->
	<bean id="userLoginFailureHandler" 
			class="edu.studySpringSecurity.service.UserLoginFailHandler"/>
	<!-- 잘못된 경로로 접근했을 때 핸들러 -->
	<bean id="userDeniedHandler"
	 		class="edu.studySpringSecurity.service.UserDeniedHandler"/>
	<!-- 로그인 확인 핸들러 -->
	<bean id="userService"
	 		class="edu.studySpringSecurity.service.UserAuthenticationService" >
	<!-- 
		"해당 핸들러에서 sqlSession.selectOne() 메소드를 사용하기 때문에, 
		생성자를 통해 sqlSession을 주입받도록 선언."
	 -->
	 		<constructor-arg name="sqlSession" ref="sqlSession" />
	</bean>
<!-- 비밀번호 비교할 암호화 객체 선언 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> 
<!-- 
	로그인 버튼 security에서 어떤 userAuthenticationService를 사용할 지와 반환된 User 객체에서
	어떤 비밀번호 암호화를  사용하여 비교 할 것인지에 대한 정보를 설정 영역 
-->	
<security:authentication-manager>
	<security:authentication-provider user-service-ref="userService">  <!-- userVO 반환 객체 참조  -->
		<security:password-encoder ref="passwordEncoder" />
	</security:authentication-provider>
</security:authentication-manager>

</beans>