보라코딩
스프링 시큐리티 JDBC 간편인증/권한처리 (BCryptPasswordEncoder 클래스) 본문
주의!!
저 파일 두개 잊지말자!
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();
}
}
}
}
}
생성된 사용자에 권한 부여하기
위의 테스트 파일에 아래 테스트 추가!
@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
'코딩 > Spring' 카테고리의 다른 글
스프링 검색처리 (0) | 2023.05.16 |
---|---|
스프링 페이징처리 paging (0) | 2023.05.16 |
스프링 시큐리티 CSRF 토큰, 로그아웃 (0) | 2023.05.15 |
스프링 시큐리티 기본 설정, 로그인 (0) | 2023.05.15 |
스프링 파일 업로드 (ajax) (0) | 2023.05.14 |