본문 바로가기

웹_프론트_백엔드/JAVA프레임윅기반_풀스택

2020.07.07

[어제 배운 Spring Security에 spring-jdbc 설정 추가하기]

1. DataSource가 필요

① 메이븐 설정 파일 pom.xml에 jdbc 라이브러리 추가

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.lec</groupId>
	<artifactId>sts18_security</artifactId>
	<name>STS18_Security</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>5.2.1.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>
	
	
	<!-- Maven 빌드를 사용하는 Spring 에서 오라클 라이브러리 추가하기 -->
	<!--dependencies 위에 설정 -->
	<repositories>
        <repository>
         <id>oracle</id>
         <name>ORACLE JDBC Repository</name>
         <url>https://code.lds.org/nexus/content/groups/main-repo</url>
        </repository>
	</repositories>
	
	
	<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.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</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>
		
		
		
		<!-- Security -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>


		<!-- dependencies 안쪽 에 설정 -->
		<!-- ojdbc6 -->
		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>
		
		<!-- spring jdbc 사용 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</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>
</project>

 

② spring-jdbc 설정 추가

** src > main > webapp > WEB-INF > spring > root-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:beans="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans 
	https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	<!-- spring-jdbc 빈 객체 생성 -->
	<!-- DataSource 객체 -->
	<beans:bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<beans:property name="url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
		<beans:property name="username" value="scott0316"/>
		<beans:property name="password" value="tiger0316"/>
	</beans:bean>
		
</beans>

 

 

2. JDBC를 이용한 인증/권한 체크 방식 
방식1. spring에서 지정된 형식의 테이블 생성하는 방식 
방식2. 기존에 작성된 데이터 베이스를 이용하는 방식

 

 

3. [방법1] spring-security 형식의 테이블 작성

1) 테이블 생성

** ERD > spring_security_oracle.erm

** ERD > spring_security_oracle.sql

/* Drop Tables */

DROP TABLE authorities CASCADE CONSTRAINTS;
DROP TABLE users CASCADE CONSTRAINTS;




/* Create Tables */

CREATE TABLE users(
	username varchar2(50) NOT NULL,
	password varchar2(50) NOT NULL,
	enabled char(1) DEFAULT '1',
	PRIMARY KEY (username)
);

CREATE TABLE authorities(
	username varchar2(50) REFERENCES users(username),
	authority varchar2(50) NOT NULL,
	PRIMARY KEY (username, authority) -- 복합키
);



/* 데이터 DML */
INSERT INTO users (username, password) VALUES ('user00', '1234');
INSERT INTO users (username, password) VALUES ('member00', '1234');
INSERT INTO users (username, password) VALUES ('admin00', '1234');

INSERT INTO authorities VALUES ('user00', 'ROLE_USER');
INSERT INTO authorities VALUES ('member00', 'ROLE_MEMBER');
INSERT INTO authorities VALUES ('admin00', 'ROLE_MEMBER');
INSERT INTO authorities VALUES ('admin00', 'ROLE_ADMIN');

-- 확인
SELECT u.username, u.password ,u.enabled, a.authority
FROM users u, authorities a
WHERE u.username = a.username;


 

2) PasswordEncoder 문제 해결(spring-security 5부터는 반드시 PasswordEncoder를 지정 필요)

** [src/main/java] com.lec.sts18_security.security > CustomNoOpPasswordEncoder.java

package com.lec.sts18_security.security;

import org.springframework.security.crypto.password.PasswordEncoder;

public class CustomNoOpPasswordEncoder implements PasswordEncoder {

	// 주어진 rawPassword를 인코딩하여 리턴, 일반적으로 SHA-1 혹은 그 이상의 암호화 알고리즘 사용
	@Override
	public String encode(CharSequence rawPassword) {
		System.out.println("encode 전 : "  + rawPassword);
		return rawPassword.toString();
	}

	// 주어진 rawPassword가 인코딩된 비번과 동일한지 판정
	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		System.out.println("matches 수행 : " + rawPassword + "::" + encodedPassword);
		return rawPassword.toString().equals(encodedPassword);
	}

}

 

** src > main > webapp > WEB-INF > spring > appServlet > 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="customAccessDenied"
		class="com.lec.sts18_security.security.CustomAccessDeniedHandler"/>
		
	<bean id="customLoginSuccess"
		class="com.lec.sts18_security.security.CustomLoginSuccessHandler"/>
		
	<bean id="customPasswordEncoder"
		class="com.lec.sts18_security.security.CustomNoOpPasswordEncoder"/>
		
	<!-- 컨테이너의 HTTP security 요소 -->
	<security:http>
		<!-- 특정 url pattern 의 요청이 들어올때 인터셉터를 이용해 접근 제한 설정 -->
		<security:intercept-url pattern="/sample/all" access="permitAll"/>
		
		<!-- /sample/member URI 요청은 ROLE_MEMBER 라는 권한이 있는 사용자만 접근 가능 -->
		<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
		
		<!-- /sample/admin URI 요청은 ROLE_ADMIN 라는 권한이 있는 사용자만 접근 가능 -->
		<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')"/>
		
		<!-- login 페이지 -->
		<!-- <security:form-login/>-->	<!-- 스프링에서 기본 제공하는 로그인 페이지 사용 -->
		<security:form-login login-page="/customLogin"
			authentication-success-handler-ref="customLoginSuccess"/>
		
		<!-- 접근 제한 메시지 처리 -->
		<!-- 
		<security:access-denied-handler error-page="/accessError"/>
		-->
		<security:access-denied-handler ref="customAccessDenied"/>
		
		<!-- 로그아웃 처리 -->
		<security:logout logout-url="/customLogout" invalidate-session="true"/>
		
	</security:http>
	
	<!-- AuthenticationManager 빈 생성, 
		  인증  (예) 로그인 -->
	<security:authentication-manager>
		<!-- UserDetailsService 사용자 인증과 권한 처리 -->
		<security:authentication-provider>
			<!-- InMemory 방식
			<security:user-service>
				<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
				<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
			</security:user-service>
			-->
			
			<!-- JDBC 사용 -->
			<security:jdbc-user-service data-source-ref="dataSource"/>
			
			<!-- PasswordEncoder 설정 -->
			<security:password-encoder ref="customPasswordEncoder"/>
			
		</security:authentication-provider>
	
	</security:authentication-manager>		

</beans>

 

 

4. [방법2] 기존에 작성된 데이터 베이스를 이용하는 방식

 : 기존에 회원 관리 테이블이 있다면,

   spring-security에서 지정한 결과를 반환하는 쿼리를 작성해 주는 작업으로도 처리가 가능


   <security:jdbc-user-service> 태그에 users-by-username-query, authorities-by-username-query 속성 지정 가능

 

1) 사용자, 권한 테이블 생성

** ERD > test_auth_oracle.erm

** ERD > test_auth_oracle.sql

/* Drop Tables */

DROP TABLE tbl_member_auth CASCADE CONSTRAINTS;
DROP TABLE tbl_member CASCADE CONSTRAINTS;




/* Create Tables */

CREATE TABLE tbl_member (
	userid varchar2(50) NOT NULL PRIMARY KEY,
	userpw varchar2(100) NOT NULL,
	username varchar2(100) NOT NULL,
	regdate date DEFAULT SYSDATE,
	updatedate date DEFAULT SYSDATE,
	enabled char(1) DEFAULT '1'
);


CREATE TABLE tbl_member_auth (
	userid varchar2(50) NOT NULL,
	auth varchar2(50) NOT NULL,
	CONSTRAINT fk_member_auth FOREIGN KEY(userid) REFERENCES tbl_member(userid),
	PRIMARY KEY(userid, auth) -- 복합키
);



-- 확인
SELECT u.userid, u.userpw, u.enabled, a.auth
FROM tbl_member u, tbl_member_auth a
WHERE u.userid = a.userid;

-- 삭제
DELETE FROM tbl_member;
DELETE FROM TBL_MEMBER_AUTH;

-- 특정 user
SELECT u.userid, u.userpw, u.enabled, a.auth
FROM tbl_member u, tbl_member_auth a
WHERE u.userid = a.userid AND u.userid = 'admin90';

 

2) 메이븐 설정 파일 pom.xml을 통해 junit, hamcrest 라이브러리 추가

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.lec</groupId>
	<artifactId>sts18_security</artifactId>
	<name>STS18_Security</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>5.2.1.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>
	
	
	<!-- Maven 빌드를 사용하는 Spring 에서 오라클 라이브러리 추가하기 -->
	<!--dependencies 위에 설정 -->
	<repositories>
        <repository>
         <id>oracle</id>
         <name>ORACLE JDBC Repository</name>
         <url>https://code.lds.org/nexus/content/groups/main-repo</url>
        </repository>
	</repositories>
	
	
	<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.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</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.12</version>
			<scope>test</scope>
		</dependency>
		
		
		<!-- ham, test 추가 -->
		<dependency>
		    <groupId>org.hamcrest</groupId>
		    <artifactId>hamcrest-all</artifactId>
		    <version>1.3</version>
		    <scope>test</scope>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-test</artifactId>
		    <version>${org.springframework-version}</version>
		    <scope>test</scope>
		</dependency>
		
		
		<!-- Security -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>


		<!-- dependencies 안쪽 에 설정 -->
		<!-- ojdbc6 -->
		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>
		
		<!-- spring jdbc 사용 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</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>
</project>

 

[추가] https://mvnrepository.com를 이용, hamcrest 라이브러리 추가

[추가] https://mvnrepository.com를 이용, spring test 라이브러리 추가

** 정상적으로 라이브러리가 추가되면 아래의 사진과 같이 확인됨

3) BCryptPasswordEncoder 암호화 처리
 : bcrypt는 대표적인 암호 인코딩 전용 해시 함수,
   특정 패스워드 암호화, 암호화된 패스워드 체크 가능, 역으로 원래 패스워드로는 못 돌림

 

** [src/main/java] com.lec.sts18_security.security > CustomNoOpPasswordEncoder.java

package com.lec.sts18_security.security;

import org.springframework.security.crypto.password.PasswordEncoder;

public class CustomNoOpPasswordEncoder implements PasswordEncoder {

	// 주어진 rawPassword를 인코딩하여 리턴, 일반적으로 SHA-1 혹은 그 이상의 암호화 알고리즘 사용
	@Override
	public String encode(CharSequence rawPassword) {
		System.out.println("encode 전 : "  + rawPassword);
		return rawPassword.toString();
	}

	// 주어진 rawPassword가 인코딩된 비번과 동일한지 판정
	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		System.out.println("matches 수행 : " + rawPassword + "::" + encodedPassword);
		return rawPassword.toString().equals(encodedPassword);
	}

}

 

4) 인코딩된 패스워드 가진 사용자 추가
 : BCryptPasswordEncoder을 이용, 패스워드 암호화된 사용자들을 추가하는 테스트 코드를 작성

 

** [src/test/java] com.lec.sts18_security > MemberTests.java

package com.lec.sts18_security;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.*;
import org.junit.Before;
import org.junit.runner.*;
import org.junit.runners.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/*
 * 스프링에서는 자동으로 클래스 간 여러 의존주입이 발생하기 때문에
 * 다른 클래스에서 작성한 코드들을 사용할 수 있지만, JUnit 은 테스트 케이스 부분만 실행하기 때문에
 * 빈 자동 등록이나 의존주입이 일어나지 않습니다.
 * 따라서! @Service 나 @Mapper 가 붙은 클래스난 인터페이스도 쓰지 못하게 됩니다.
 * 이럴때는
 * @RunWith와 @ContextConfiguration을 이용합니다
 * 
 * 위와 같이 하면 JUnit 테스트를 실행할때 
 * @RunWith의 SpringJUnit4ClassRunner 클래스가 
 * @ContextConfiguration에 적어 놓은 파일들을 같이 실행시킵니다. 
 * root-context.xml과 security-context.xml을 실행시켜 빈 등록과 의존 주입을 실행시키는 것입니다
 */

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
	"file:src/main/webapp/WEB-INF/spring/root-context.xml",
	"file:src/main/webapp/WEB-INF/spring/appServlet/security-context.xml"
})
// 메소드 이름 순으로 테스트 진행되는 어노테이션
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MemberTests {
	
	// 자동 주입받을 PasswordEncoder와 DataSource 객체
	private PasswordEncoder pwencoder;
	private DataSource ds;
	
	public final PasswordEncoder getPwencoder() {return pwencoder;}
	@Autowired
	public final void setPwencoder(PasswordEncoder pwencoder) {this.pwencoder = pwencoder;}
	public final DataSource getDs() {return ds;}
	@Autowired
	public final void setDs(DataSource ds) {this.ds = ds;}
	
	Connection conn = null;
	PreparedStatement pstmt = null;

	final String SQL_INSERT_MEMBER 
		= "INSERT INTO tbl_member(userid, userpw, username) VALUES(?, ?, ?)";
	final String SQL_INSERT_AUTH
		= "INSERT INTO tbl_member_auth(userid, auth) VALUES(?, ?)";
	
	@Before
	public void initialize() {
		System.out.println("MemberTests 시작");
		try {
			conn = ds.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	@After
	public void finalize() {
		System.out.println("MemberTests 종료");
		try {
			if(conn != null) {
				conn.close();
				conn = null;
			} 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testA() {
		System.out.println("testA() 실행");
		
		if(conn == null) {return;}
		
		int cnt = 0;
		
		String userid = "", userpw = "", username = "";
	
		try {
			pstmt = conn.prepareStatement(SQL_INSERT_MEMBER);
			// 100명의 테스트용 데이터 생성
			for(int i = 0; i < 100; i++) {
				userpw = "pw" + i;   // 패스워드 pw0, pw1, ... 생성
				
				// 일반사용자: 운영자: 관리자  80:10:10 명 생성
				if(i < 80) {
					userid = "user" + i;
					username = "일반사용자" + i;
				} else if (i < 90) {
					userid = "member" + i;
					username = "회원" + i;
				} else {
					userid = "admin" + i;
					username = "관리자" + i;
				}
				
				cnt = 0;
				try {
					pstmt.setString(1, userid);
					pstmt.setString(2, pwencoder.encode(userpw));  // 패스워드 인코딩 
					pstmt.setString(3, username);
					cnt = pstmt.executeUpdate();
				} catch(Exception e) {
					System.out.println(e.getMessage());
				}
				
				if(cnt > 0) {
					System.out.println("INSERT_MEMBER 성공]" + userid + ":" + userpw + ":" + username);
				} else {
					System.out.println("INSERT_MEMBER 실패]" + userid + ":" + userpw + ":" + username);
				}
				
			} // end for
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	} // end testA()
	
	
	@Test
	public void testB() {
		System.out.println("testB() 실행");
		
		if(conn == null) {return;}
		
		int cnt = 0;
		String userid = "", auth = "";
		
		try {
			pstmt = conn.prepareStatement(SQL_INSERT_AUTH);

			for(int i = 0; i < 100; i++) {
				if(i < 80) {
					userid = "user" + i;
					auth = "ROLE_USER";
				} else if(i < 90) {
					userid = "member" + i;
					auth = "ROLE_MEMBER";
				} else {
					userid = "admin" + i;
					auth = "ROLE_ADMIN";
				}
				cnt = 0;
				
				try {
					pstmt.setString(1, userid);
					pstmt.setString(2, auth);
					cnt = pstmt.executeUpdate();	
					
					if(cnt > 0) {
						System.out.println("INSERT_AUTH 성공] " + userid + ":" + auth);
					} else {
						System.out.println("INSERT_AUTH 실패] " + userid + ":" + auth);
					}
					
					// admin 의 경우 ROLE_MEMBER 도 추가
					if(userid.startsWith("admin")) {
						auth = "ROLE_MEMBER"; 
						pstmt.setString(1, userid);
						pstmt.setString(2, auth);
						cnt = pstmt.executeUpdate();
						
						if(cnt > 0) {
							System.out.println("INSERT_AUTH 성공] " + userid + ":" + auth);
						} else {
							System.out.println("INSERT_AUTH 실패] " + userid + ":" + auth);
						}
					}
					
				} catch(Exception e) {
					System.out.println(e.getMessage());
				}

			} // end for
			
			
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
	} // end testB()
	

} // end TEST

 

** MemberTests.java 결과값

 

 

5. javaProj2

** [src/test/java] com.mvn.javaproj2 > TestJunit1.java

package com.mvn.javaproj2;

import static org.junit.Assert.*;

import org.junit.Test;

/*
 * 1. void assertEquals(boolean expected, boolean actual)
 * 2. void assertFalse(boolean condition)    // false 인지 체크
 * 3. void assertNotNull(Object object)   // Object 가 null 이 아닌지 체크
 * 4. void assertNull(Object object)   // Object 가 null 인지 체크
 * 5. void assertTrue(boolean condition)  // true 인지 체크
 * 6. void fail()   // 무조건 fail
 * 
*/

public class TestJunit1 {

	@Test
	public void test() {
		int num = 5;
		String temp = null;
		String str = "안녕하세요";
		
		//assertEquals("안녕하세요1", str);
		assertEquals("안녕하세요", str);
		assertFalse(num > 6);
		//assertFalse(num > 2);
		
		//assertNotNull(temp);
		assertNull(temp);
		
		System.out.println(12.3 / 4.1);
		
		// 실수는 오차가 발생할 수 있음 
		// double/float 실수 연산 값의 오차범위 delta 값 
		//assertEquals(3.0, 12.3 / 4.1);	// FAIL
		assertEquals(3.0, 12.3 / 4.1, 0.1);	// pass
	}

}

 

** [src/test/java] com.mvn.javaproj2 > TestJunit2.java

package com.mvn.javaproj2;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import junit.framework.TestCase;

public class TestJunit2 extends TestCase {
	
	@Before
	public void before() {
		System.out.println("[before()]");
	}
	@After
	public void after() {
		System.out.println("[after()]");
	}
	
	@BeforeClass
	public static void beforeClass() {
		System.out.println("<<beforeClass()>>");
	}
	@AfterClass
	public static void afterClass() {
		System.out.println("<<afterClass()>>");
	}

	@Test
	public void testA() {
		System.out.println("testA()");
		System.out.println("No. of Test Case = " + this.countTestCases());
		System.out.println("Test Case Name = " + this.getName());
	}
	@Test
	public void testB() {
		System.out.println("testB()");
		System.out.println("No. of Test Case = " + this.countTestCases());
		setName("B테스트입니다.");
		System.out.println("Test Case Name = " + this.getName());
	}
	@Test
	public void testC() {
		System.out.println("testC()");
		System.out.println("No. of Test Case = " + this.countTestCases());
		System.out.println("Test Case Name = " + this.getName());
	}
	@Test
	public void testD() {
		System.out.println("testD()");
		System.out.println("No. of Test Case = " + this.countTestCases());
		System.out.println("Test Case Name = " + this.getName());
	}

}

 

** [src/test/java] com.mvn.javaproj2 > TestParameter.java

package com.mvn.javaproj2;

import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.Collection;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
 * JUnit 파라미터화 테스트(Parameterized Test)
 * 
 * 동일한 테스트를 @Parameters 컬렉션의 원소 개수만큼 반복 실행
 * Parameterized 클래스는 JUnit이 제공하는 많은 테스트 러너중 하나
 */

@RunWith(value = Parameterized.class)
public class TestParameter {
	
	private int expected;
	private int valueOne;
	private int valueTwo;
	
	@Parameters
	public static Collection<Integer[]> getTestParameters() {
		return Arrays.asList(new Integer[][] {
			{2, 1, 1},	// expected, valueOne, valueTwo
			{3, 2, 1},
			{4, 3, 1},
			{5, 2, 3}
			//, {3, 1, 1}
		});
	}
	
	public TestParameter(int expected, int valueOne, int valueTwo) {
		super();
		System.out.println("TestParameter() 생성");
		this.expected = expected;
		this.valueOne = valueOne;
		this.valueTwo = valueTwo;
	}

	@Test
	public void sum() {
		Calculator cal = new Calculator();
		assertEquals(expected, cal.add(valueOne, valueTwo));
		System.out.println("테스트 통과: " + expected + ", " + valueOne + ", " + valueTwo);
	}	
	
	// 생성자는 4번 생성되었지만, 놀랍게도 @BeforeClass는 1번만 출력된다! 
	@BeforeClass
	public static void beforeClass() {
		System.out.println("@BeforeClass");
	}

}

'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글

2020.07.08  (0) 2020.07.08
애플리케이션_테스트 시험(제출 코드와 풀이)  (0) 2020.07.07
2020.07.06  (0) 2020.07.06
2020.07.06  (0) 2020.07.06
2020.07.03  (0) 2020.07.03