보라코딩

스프링 시큐리티 JDBC 간편인증/권한처리 (BCryptPasswordEncoder 클래스) 본문

코딩/Spring

스프링 시큐리티 JDBC 간편인증/권한처리 (BCryptPasswordEncoder 클래스)

new 보라 2023. 5. 15. 18:10

주의!!

저 파일 두개 잊지말자!

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

 

 

 

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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


<!-- Root Context: defines shared resources visible to all other web components -->

<context:annotation-config></context:annotation-config>

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">

<property name="driverClassName"
value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
<property name="jdbcUrl"
value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>
<property name="username" value="book_ex"></property>
<property name="password" value="book_ex"></property>

</bean>

<!-- HikariCP configuration -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>

<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>


</beans>

 

 

 

DB 테이블 생성

create table users(
    username varchar2(50) NOT NULL PRIMARY KEY,
    PASSWORD VARCHAR2(50) NOT NULL,
    ENABLED CHAR(1) DEFAULT '1'
);
    
CREATE TABLE AUTHORITIES(
    USERNAME VARCHAR2(50) NOT NULL,
    AUTHORITY VARCHAR2(50) NOT NULL,
    CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));
);

INSERT INTO USERS (USERNAME, PASSWORD) VALUES ('user00', 'ROLE_USER');
INSERT INTO USERS (USERNAME, PASSWORD) VALUES ('member00', 'PW00');    
INSERT INTO USERS (USERNAME, PASSWORD) VALUES ('admin00', 'PW00');

INSERT INTO AUTHORITIES (USERNAME, AUTHORITY) VALUES ('user00', 'ROLE_USER');
INSERT INTO AUTHORITIES (USERNAME, AUTHORITY) VALUES ('member00', 'ROLE_MANAGER');
INSERT INTO AUTHORITIES (USERNAME, AUTHORITY) VALUES ('admin00', 'ROLE_MANAGEER');
INSERT INTO AUTHORITIES (USERNAME, AUTHORITY) VALUES ('admin00', 'ROLE_ADMIN');


 

 

 

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.mystudy.security.CustomAccessDeniedHandler"></bean>

<bean id="customLoginSuccess"
class="com.mystudy.security.CustomLoginSuccessHandler"></bean>

<bean id="customPasswordEncoder" 
class="com.mystudy.security.CustomNoOpPasswordEncoder"></bean>




<security:http>

<security:intercept-url pattern="/sample/all"
access="permitAll" />

<security:intercept-url
pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />

<security:intercept-url pattern="/sample/admin"
access="hasRole('ROLE_ADMIN')" />

<security:access-denied-handler
ref="customAccessDenied" />

<security:form-login login-page="/customLogin"
authentication-success-handler-ref="customLoginSuccess" />

<security:logout logout-url="/customLogout"
invalidate-session="true" />

</security:http>

<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource" />

<security:jdbc-user-service 
data-source-ref="dataSource" 
users-by-username-query="select userid , 
userpw, enabled from tbl_member where userid = ? " 
authorities-by-username-query="select 
userid, auth from tbl_member_auth where userid = ? " /> 

  <security:password-encoder ref="customPasswordEncoder" />
<!--  <security:password-encoder ref="bcryptPasswordEncoder" />  -->
 
 
<!--  <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> -->

</security:authentication-provider>
</security:authentication-manager>

</beans>






 

CustomNoOpPasswordEncoder.java     (뒤에서 사용안함)

 

 

package com.mystudy.security;

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

import lombok.extern.log4j.Log4j;

@Log4j
public class CustomNoOpPasswordEncoder implements PasswordEncoder {

public String encode(CharSequence rawPassword) {

log.warn("before encode :" + rawPassword);

return rawPassword.toString();
}

public boolean matches(CharSequence rawPassword, String encodedPassword) {

log.warn("matches: " + rawPassword + ":" + encodedPassword);

return rawPassword.toString().equals(encodedPassword);
}

}

 

 

 


여기까지  준비


 

인증/권한을 위한 테이블 설계


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));

 

 

 

BCryptPasswordEncoder  클래스 이용한 패스워드 보호 (해시함수)
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.mystudy.security.CustomAccessDeniedHandler"></bean>

<bean id="customLoginSuccess"
class="com.mystudy.security.CustomLoginSuccessHandler"></bean>

<!--  <bean id="customPasswordEncoder" 
class="com.mystudy.security.CustomNoOpPasswordEncoder"></bean> -->

<bean id="bcryptPasswordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />


<security:http>

<security:intercept-url pattern="/sample/all"
access="permitAll" />

<security:intercept-url
pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />

<security:intercept-url pattern="/sample/admin"
access="hasRole('ROLE_ADMIN')" />

<security:access-denied-handler
ref="customAccessDenied" />

<security:form-login login-page="/customLogin"
authentication-success-handler-ref="customLoginSuccess" />

<security:logout logout-url="/customLogout"
invalidate-session="true" />

</security:http>





<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource" />

 <security:password-encoder ref="bcryptPasswordEncoder" />
 
<!-- <security:password-encoder ref="customPasswordEncoder" /> -->
 
<!--  <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> -->

</security:authentication-provider>
</security:authentication-manager>

</beans>


 

 

인코딩된 패스워드를 가지는 사용자 추가
pom.xml    (예전에 추가했긴함)

 

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
</dependency>

 

 

 

테스트 진행

 

 

MemberTests.java

 

package com.mystudy.security;

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

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
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;

import java.sql.Connection;

import lombok.extern.log4j.Log4j;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
{"file:src/main/webapp/WEB-INF/spring/root-context.xml",
 "file:src/main/webapp/WEB-INF/spring/security-context.xml"})
@Log4j
public class MemberTests {

@Autowired
private PasswordEncoder pwencoder;

@Autowired
private DataSource ds;

@Test
public void testInsertMember() {


String sql = "insert into tbl_member(userid, userpw, username)"
+ " values (?,?,?)";

for(int i=0; i<100; i++) {
Connection con = null;
PreparedStatement pstmt = null;

try {
con = ds.getConnection();
pstmt = con.prepareStatement(sql);

pstmt.setString(2, pwencoder.encode("pw"+1));

if(i<80) {
pstmt.setString(1,  "user"+i);
pstmt.setString(3,  "일반사용자"+i);
} else if (i<90) {
pstmt.setString(1,  "manager"+i);
pstmt.setString(3,  "운영자"+i);
} else {
pstmt.setString(1,  "admin"+i);
pstmt.setString(3,  "관리자"+i);
}

pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt!=null)
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
if(con!=null)
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}

}

}

}
}

 

 

 

 

 

 

DB에 이렇게 데이터 생성됨

 

 

 

 

생성된 사용자에 권한 부여하기
위의 테스트 파일에 아래 테스트 추가!

 

@Test
public void testInsertAuth() {


String sql = "insert into tbl_member_auth(userid, auth)"
+ " values (?,?)";

for(int i=0; i<100; i++) {
Connection con = null;
PreparedStatement pstmt = null;

try {
con = ds.getConnection();
pstmt = con.prepareStatement(sql);

pstmt.setString(2, pwencoder.encode("pw"+i));

if(i<80) {
pstmt.setString(1,  "user"+i);
pstmt.setString(2,  "ROLE_USER");
} else if (i<90) {
pstmt.setString(1,  "manager"+i);
pstmt.setString(2,  "ROLE_MEMBER");
} else {
pstmt.setString(1,  "admin"+i);
pstmt.setString(2,  "ROLE_ADMIN");
}

pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt!=null)
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
if(con!=null)
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}

}

}

}

 

 

 

 

 

쿼리를 이용하는 인증
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.mystudy.security.CustomAccessDeniedHandler"></bean>

<bean id="customLoginSuccess"
class="com.mystudy.security.CustomLoginSuccessHandler"></bean>

<bean id="bcryptPasswordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />


<security:http>

<security:intercept-url pattern="/sample/all"
access="permitAll" />

<security:intercept-url
pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />

<security:intercept-url pattern="/sample/admin"
access="hasRole('ROLE_ADMIN')" />

<security:access-denied-handler
ref="customAccessDenied" />

<security:form-login login-page="/customLogin"
authentication-success-handler-ref="customLoginSuccess" />

<security:logout logout-url="/customLogout"
invalidate-session="true" />

</security:http>





<security:authentication-manager>
<security:authentication-provider>

 <security:jdbc-user-service data-source-ref="dataSource" 
users-by-username-query="select userid , 
userpw, enabled from tbl_member where userid = ? " 
authorities-by-username-query="select 
userid, auth from tbl_member_auth where userid = ? " />  

  <security:password-encoder ref="bcryptPasswordEncoder" />
 
</security:authentication-provider>
</security:authentication-manager>

</beans>






 

 

 

https://boracoding.tistory.com/171