Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags more
Archives
Today
Total
관리 메뉴

기록

JAVA SPRING 시큐리티 연습 본문

JAVA

JAVA SPRING 시큐리티 연습

9400 2023. 2. 14. 10:12

 

먼저 테이블 만들기 

CREATE TABLE MEM(
    USER_NO NUMBER,
    USER_ID VARCHAR2(50),
    USER_PW VARCHAR2(100),
    USER_NAME VARCHAR2(300),
    COIN NUMBER,
    REG_DATE DATE,
    UPD_DATE DATE,
    ENABLED VARCHAR2(1),
    CONSTRAINT PK_MEM PRIMARY KEY(USER_NO)
);

CREATE TABLE MEM_AUTH(
    USER_NO NUMBER,
    AUTH VARCHAR2(50),
    CONSTRAINT PK_MEM_AUTH PRIMARY KEY(USER_NO, AUTH),
    CONSTRAINT FK_MEM_AUTH FOREIGN KEY(USER_NO) REFERENCES MEM(USER_NO)
);

mem테이블 (1)

mem_auth테이블(N)

SELECT A.USER_NO, A.USER_ID, A.USER_PW, A.USER_NAME, A.COIN, A.REG_DATE, A.UPD_DATE, A.ENABLED,
        B.USER_NO, B.AUTH
FROM MEM A LEFT OUTER JOIN MEM_AUTH B
ON(A.USER_NO = B.USER_NO)
WHERE A.USER_ID = 'member1';

 

 

 

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">
 	
 	<!-- customAccessDenied를 자바빈(객체)으로 등록함/ 권한불일치시 다음의 클래스로 이동 -->
 	<bean id="customAccessDenied" class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
 	
 	<!-- 로그인 성공시 다음의 클래스로 이동 -->
 	<bean id="customLoginSuccess" class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>
 	
 	<!-- 사용자가 정의한 비밀번호 암호화 처리기를 빈으로 등록함 -->
 	<bean id="customPassswordEncoder" class="kr.or.ddit.security.CustomNoOpPasswordEncoder"></bean>
 	
 	<!-- 스프링 시큐리티에서 제공하는 BCryptPasswordEncoder 클래스를 자바빈으로 등록함 -->
<!--  	<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean> -->
 	
 	<!-- 사용자정의 사용자 상세 기능  **** 중요-->
 	<bean id="customUserDetailsService" class="kr.or.ddit.security.CustomUserDetailsService"></bean>
 	
 	
 	<bean id="CustomLogoutSuccessHandler" class="kr.or.ddit.security.CustomLogoutSuccessHandler"></bean>
 	
 	
 	<!-- xmlns : xml namespace의 약자
 		Role : 권한(authorization)
 		permitAll : 누구나 접근 가능
 		hasRole : 권한을 갖은가인가?
 	 -->
 	<security:http>
 		<!-- URI 패턴으로 접근 제한을 설정 -->
 		<security:intercept-url pattern="/board/list" access="permitAll"/>
 		<security:intercept-url pattern="/board/register" access="hasRole('ROLE_MEMBER')"/>
 	
 		<security:intercept-url pattern="/notice/list" access="permitAll"/>
 		<security:intercept-url pattern="/notice/register" access="hasRole('ROLE_ADMIN')"/>
 		
 	
 		<!-- 폼 기반 인증 기능을 사용 -->
 		<!-- 접근 제한에 걸리면 시큐리티가 기본적으로 제공하는 로그인 페이지로 이동 -->
 <!-- 		<security:form-login/> -->
 
 		<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함 -->
 		<security:form-login login-page="/login" 
 			authentication-success-handler-ref="customLoginSuccess"/>
 		
 		<!-- 로그인이 된 회원중에 권한이 없을때.. -->
 		<!-- 접근(access) 거부(denied) 처리자(handler)의 URI를 지정 -->
<!--  		<security:access-denied-handler error-page="/accessError"/> -->

		
		<!-- 등록한 CustomAccessDeniedHandler를 접근 거부 처리자로 지정함 
		customAccessDenied 객체를 reference(참조-바라본다)함-->
		<security:access-denied-handler ref="customAccessDenied"/>

		<!-- 데이터소스를 지정하고 테이블을 이용해서 기존 로그인 정보를 기록
		쿠키의 유효시간을 지정함
		token-validity-seconds : 쿠키의 유효시간(초) 604800초는 7일 -->
		
		<security:remember-me data-source-ref="dataSource" 
		token-validity-seconds="604800"/>
		

		<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화함 
		customLogoutSuccessHandler(사용자정의 로그아웃 성공 처리자)
		JSESSION_ID : 웹브라우저(유일한 세션)의 유일한 세션값을 쿠키에 담고있음.-->
		<security:logout logout-url="/logout" invalidate-session="true"
			success-handler-ref="CustomLogoutSuccessHandler"
			delete-cookies="remember-me,JSESSION_ID" />
 	</security:http>
 	
 	
 	<!-- authentication : 인증(로그인) 
 	1) 회원 게시판(board)
 		가) 목록("/board/list") : 모두가 접근 가능
 		나) 등록("/board/register") : 로그인한 회원만 접근가능
 	2) 공지사항 게시판(notice)
 		가) 목록("/notice/list") : 모두가 접근 가능
 		나) 등록 ("/notice/register"): 로그인한 관리자만 접근가능
 		
 	1  회원(USERS)테이블 : USERNAME,PASSWORD, ENABLED 
 	
 	N 권한(AUTH)테이블 : USERNAME, AUTHRIZE
 	-->
 	
 	<security:authentication-manager>
 		<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정 
 		authentication-provider : 인증(로그인) 제공자
 		-->
 		<security:authentication-provider user-service-ref="customUserDetailsService">
 			<!-- DB를 사용하겠다 라는 의미. 데이터 소스를 지정.//dataSource => root-context에 등록한 bean(객체) -->
<!--  			<security:jdbc-user-service data-source-ref="dataSource"/> -->
 			
 			<!-- 사용자가 정의한 비밀번호 암호화 처리기를 지정(암호화를 안쓰겠다는 의미)-->
			<security:password-encoder ref="customPassswordEncoder" />
			
			<!-- BCryptPasswordEncoder비밀번호 암호화 처리기를 사용하겠다는 뜻 -->
<!-- 			<security:password-encoder ref="bcryptPasswordEncoder" /> -->


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

 

<!-- 사용자정의 사용자 상세 기능  **** 중요-->
 	<bean id="customUserDetailsService" class="kr.or.ddit.security.CustomUserDetailsService"></bean>

 

 

CustomUserDetailsService 클래스 

package kr.or.ddit.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import kr.or.ddit.mapper.EmpMapper;
import kr.or.ddit.vo.MemVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomUserDetailsService implements UserDetailsService {

	//DI(의존성주입)
	@Autowired
	EmpMapper empMapper;
	
	//요청파라미터 <input type="text" name="username" ... >
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//파라미터 준비(public MemVO memLogin(MemVO memVO))
		MemVO memVO = new MemVO();
		//WHERE A.USER_ID = #{userId}
		memVO.setUserId(username);
		
		memVO = empMapper.memLogin(memVO);
		
		log.warn("EmpMapper에 의해 쿼리를 실행할 것임 :"+memVO);
		
		
		//3항 연산자. memVO가 null이면 null을 리턴하고, null이 아니면 USER를 리턴
		return memVO==null?null:new CustomUser(memVO);
        //return 되는값은 스프링 시큐리티에 보냄
	}

}

 

CustomUser 클래스 

package kr.or.ddit.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;

import kr.or.ddit.vo.MemAuthVO;
import kr.or.ddit.vo.MemVO;

//User : 스프링 시큐리티가 제공하는 있는 사용자 정보 클래스
public class CustomUser extends User {
	//이 memVO 객체는 JSP에서 사용할 수 있음.
	private MemVO memVO;

	public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super(username, password, authorities);
	}

	//생성자
	//memVO : select한 사용자 및 권한 정보가 들어있음
	//memVO 타입의 객체 memVO를 스프링 시큐리티에서 제공해주고 있는 UserDetails타입으로 변환
	//스프링 시큐리티야 회원정보를 보내줄테니.. 이제부터 니가 좀 관리해줘! 
	public CustomUser(MemVO memVO) {
		//1)username 2)password 3)authorities
		//memVO.getMemAuthVOList()
		// 2 ROLE_ADMIN
		// 2 ROLE_MEMBER
		//memVO.getMemAuthVOList().stream()
		// 2 ROLE_ADMIN 2.ROLE_MEMBER
		
		//방법1)
//		super(memVO.getUserId(),memVO.getUserPw(),
//				memVO.getMemAuthVOList().stream().map(auth->new SimpleGrantedAuthority(auth.getAuth()))
//				.collect(Collectors.toList()));
//		this.memVO = memVO;
		
		//방법2) 아래의 public static List<SimpleGrantedAuthority> getCollect(MemVO memVO) 필요
		super(memVO.getUserId(),memVO.getUserPw(),
				getCollect(memVO));
		this.memVO = memVO;
		
	}
	
	public static List<SimpleGrantedAuthority> getCollect(MemVO memVO){
		List<SimpleGrantedAuthority> authorities 
		 = new ArrayList<SimpleGrantedAuthority>();
		
		/*
		 2 ROLE_ADMIN
		 2 ROLE_MEMBER
		 */
		List<MemAuthVO> memAuthVOList = memVO.getMemAuthVOList();
		
		for(MemAuthVO memAuthVO : memAuthVOList) {
			//memAuthVO.getAuth() : ROLE_ADMIN
			SimpleGrantedAuthority authrity = new SimpleGrantedAuthority(memAuthVO.getAuth());
			authorities.add(authrity);
		}
		return authorities;
		
	}

	public MemVO getMemVO() {
		return memVO;
	}

	public void setMemVO(MemVO memVO) {
		this.memVO = memVO;
	}
	
}
Comments