Spring

[Spring] JDBC 이용한 인증

아잠만_ 2024. 8. 12. 15:03

sql

CREATE

CREATE TABLE USERS(
    USERNAME VARCHAR2(150) NOT NULL,
    PASSWORD VARCHAR2(150) NOT NULL,
    ENABLED VARCHAR2(1),
    Constraint PK_USERS PRIMARY KEY (USERNAME)
)

CREATE TABLE AUTHORITIES(
    USERNAME VARCHAR2(150) NOT NULL,
    AUTHORITY VARCHAR2(150) NOT NULL,
    CONSTRAINT PK_AUTH PRIMARY KEY (USERNAME, AUTHORITY),
    CONSTRAINT FK_AUTH_USER FOREIGN KEY (USERNAME)
                REFERENCES USERS(USERNAME)
)

INSERT

INSERT INTO USERS(USERNAME, PASSWORD, ENABLED)
VALUES('user','java', '1');
INSERT INTO USERS(USERNAME, PASSWORD, ENABLED)
VALUES('member','java', '1');
INSERT INTO USERS(USERNAME, PASSWORD, ENABLED)
VALUES('admin','java', '1');

COMMIT;

INSERT INTO AUTHORITIES(USERNAME, AUTHORITY)
VALUES('user', 'ROLE_USER');
INSERT INTO AUTHORITIES(USERNAME, AUTHORITY)
VALUES('member', 'ROLE_MEMBER');
INSERT INTO AUTHORITIES(USERNAME, AUTHORITY)
VALUES('admin', 'ROLE_ADMIN');
INSERT INTO AUTHORITIES(USERNAME, AUTHORITY)
VALUES('admin', 'ROLE_MEMBER');

COMMIT;

데이터 확인

SELECT *
FROM USERS A
LEFT OUTER JOIN Authorities B ON (A.USERNAME=B.USERNAME)

WEB-INF/spring/security-context.xml

<security:jdbc-user-service data-source-ref="DB객체"/>
<security:password-encoder ref="인코더Bean"/>

<?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="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
	<!-- 로그인 성공 클래스 객체 생성 -->
	<bean id="customLoginSuccess" class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>		
	<!--  -->
	<bean id="customPasswordEncoder" class="kr.or.ddit.security.CustomNoOpPasswordEncoder"></bean>
	<security:http>
		<security:intercept-url pattern="/board/list" access="permitAll"/>
		<security:intercept-url pattern="/board/regist" access="hasRole('ROLE_MEMBER')"/>
		<security:intercept-url pattern="/notice/list" access="permitAll"/>
		<security:intercept-url pattern="/notice/regist" access="hasRole('ROLE_ADMIN')"/>
		<!-- 폼 기반 인증 기능을 사용 -->
		<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함
		사용자가 정의한 class를 로그인 성공 처리자로 지정 (authentication-success-handler-ref) -->
		<security:form-login login-page="/login" authentication-success-handler-ref="customLoginSuccess"/>
		
		<!-- //// 방법 1. URI로 요청하는 방법 error-page //// -->
		<!-- 접근 거부 처리자(HTTP 상태 403 - 금지됨 : 권한 없음) 
		로그인은 됐지만 요청URI에 대한 권한이 없다면 /accessError 요청 URI로 자동 재요청됨
		-->
<!-- 		<security:access-denied-handler error-page="/accessError"/> -->
		<!-- //// 방법 2. 등록한 사용자 정의 class를 접근 거부 처리자로 지정 ref //// -->
		<security:access-denied-handler ref="customAccessDenied"/>
	</security:http>
	
	<!-- 스프링 시큐리니티 5부터 기본적으로 PasswordEncoder를 지정해야 하는데,
      그 이유는 사용자 테이블(USERS)에 비밀번호를 암호화하여 저장해야 하므로..
      우리는 우선 비밀번호를 암호화 처리 하지 않았으므로
      암호화 하지 않는 PasswordEncoder를 직접 구현하여 지정하기로 함
      noop : no option password
    -->
	<security:authentication-manager>
		<security:authentication-provider>
<!--  			<security:user-service> -->
 			<!-- name 아이디, authorities 권한 --> 
<!-- 				<security:user name="member" password="{noop}java" authorities="ROLE_MEMBER"/> -->
<!-- 				<security:user name="admin" password="{noop}java" authorities="ROLE_MEMBER, ROLE_ADMIN"/> -->
<!-- 			</security:user-service> -->
			<!-- 데이터 소스를 지정함 -->
			<security:jdbc-user-service data-source-ref="dataSource"/> <!-- root-context에 있는 bean id -->
			<!-- 사용자가 정의한 비밀번호 암호화 처리기를 지정함 -->
			<security:password-encoder ref="customPasswordEncoder"/>
		</security:authentication-provider>
	</security:authentication-manager>
</beans>

CustomNoOpPasswordEncoder.java

package kr.or.ddit.security;

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

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomNoOpPasswordEncoder implements PasswordEncoder{

	@Override
	public String encode(CharSequence rawPassword) {
		// 비밀번호를 받아서 인코딩 해주는 메서드
		// but, 아무것도 안하기로 함
		log.info("before encode : "+rawPassword);
		return rawPassword.toString();
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		// 비밀번호를 받은 거랑 DB의 비밀번호랑 비교
		log.warn("matches : "+rawPassword + " < >  "+encodedPassword);
		// 일치 true, 불일치 false
		return rawPassword.toString().equals(encodedPassword);
	}

}