반응형

 

로그인 성공 처리

 

: 로그인을 성공한 후에 로그인 이력 로그를 기록하는 등의 동작을 하고 싶은 경우 사용함

 

 

security-context.xml

<security:form-login login-page="/login"/>를 수정

<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함
사용자 정의 로그인 성공 처리자를 지정함 -->
<security:form-login login-page="/login" 
    authentication-success-handler-ref="customLoginSuccess"/>

 

<beans/> 안에 추가함

<bean id="customLoginSuccess" class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>

 

 

CustomLoginSuccessHandler.java

package kr.or.ddit.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import lombok.extern.slf4j.Slf4j;

/*   /notice/register -> loginForm -> 로그인 -> CustomLoginSuccessHandler(성공)
-> 사용자 작업.. -> /notice/register 로 리다이렉트 해줌
(스프링 시큐리티에서 기본적으로 사용되는 구현 클래스) 
*/
@Slf4j
public class CustomLoginSuccessHandler extends 
	SavedRequestAwareAuthenticationSuccessHandler{ //로그인 성공 핸들러를 상속 받음
	
	//부모 클래스의 메소드를 재정의
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication auth) throws ServletException, IOException {
		
		log.info("onAuthenticationSuccess 왔다");
		
		//auth.getPrincipal() : 사용자 정보를 가져옴 (정해진 이름을 써줘야지만 값을 가져올 수 있음)
		//시큐리티에서 사용자 정보는 User 클래스의 객체로 저장됨(CustomUser.java를 참고)
		User costomUser = (User)auth.getPrincipal();
		
		//사용자의 아이디를 리턴 받기
		log.info("username : " + costomUser.getUsername());
		
		//auth.getAuthorities() -> 권한들(ROLE_MEMBER,ROLE_ADMIN)
		//authority.getAuthority() : ROLE_MEMBER
		List<String> roleNames = new ArrayList<String>();
		auth.getAuthorities().forEach(authority->{
			roleNames.add(authority.getAuthority());
		});
		
		log.info("roleNames : " + roleNames);
		
		//부모에게 줌
		super.onAuthenticationSuccess(request, response, auth);
	}

}

 

결과 화면1-1 : http://localhost/notice/register 로 들어올 시 admin / 1234로 로그인

 

결과 화면12-2 : 로그인 성공 후 콘솔창에 찍힘

 

 

 

로그아웃 처리

 

 

security-context.xml

</security:http> 안에 추가

<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화(session.invalidate())함 
/logout : post방식 요청URI -> form의 action="/logout"에서 사용 -->
<security:logout logout-url="/logout" invalidate-session="true" />

 

 

aside.jsp

추가

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>

 

변경

	<!-- Sidebar -->
	<div class="sidebar">
		<!-- Sidebar user panel (optional) -->
		<!-- /// 로그인 안함 시작 /// -->
		<!-- isAnonymous() 는 로그인 안 했을 때 true -> 아래 코드 실행 -->
		<sec:authorize access="isAnonymous()"> <!-- 인가 : 권한 -->
			<div class="user-panel mt-3 pb-3 mb-3 d-flex">
				<div class="image">
					<img src="/resources/adminlte/dist/img/user2-160x160.jpg"
						class="img-circle elevation-2" alt="User Image">
				</div>
				<div class="info">
					<a href="#" class="d-block">Alexander Pierce</a>
				</div>
			</div>
		</sec:authorize>
		<!-- /// 로그인 안함 끝 /// -->
		
		<!-- /// 로그인 함 시작 /// -->
		<sec:authorize access="isAuthenticated()">
			<!-- principal : 사용자정보 객체 -->
<%-- 			<sec:authentication property="principal"/> --%>
			<div class="user-panel mt-3 pb-3 mb-3 d-flex">
				<div class="image">
					<img src="/resources/upload/mang6.jpg"
						class="img-circle elevation-2" alt="User Image">
				</div>
				<div class="info">
					<a href="#" class="d-block">개똥이님 환영합니다.</a>
					<form action="/logout" method="post"> <!-- 꼭 post여야함 -->
						<button type="submit" class="btn btn-block btn-secondary btn-xs">로그아웃</button>
						<sec:csrfInput/>
					</form>
				</div>
			</div>
		</sec:authorize>
		<!-- /// 로그인 함 끝 /// -->

 

 

결과 화면2 : 로그인 후 화면

 

결과 화면3 : 로그아웃 후 화면

 

 

 

JDBC 이용한 인증/인가 처리

 

 

테이블 생성

CREATE TABLE USERS(
    USERNAME VARCHAR2(150),
    PASSWORD VARCHAR2(150),
    ENABLED VARCHAR2(1),
    CONSTRAINT PK_USERS PRIMARY KEY(USERNAME)
);


CREATE TABLE AUTHORITIES(
    USERNAME VARCHAR2(150),
    AUTHORITY VARCHAR2(150),
    CONSTRAINT PK_AUTH PRIMARY KEY(USERNAME, AUTHORITY),
    CONSTRAINT FK_AUTH FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME) -- 다른 테이블을 참조함
);

 

USERS 테이블 정보

 

 

데이터 삽입

기존 테이블에 데이터가 없는 경우 일일히 데이터를 넣는 걸 추천함

INSERT INTO USERS(USERNAME,PASSWORD)
SELECT EMP_NO, 'java' FROM EMPLOYEE;

COMMIT;

INSERT INTO AUTHORITIES(USERNAME,AUTHORITY)
SELECT EMP_NO, 'ROLE_MEMBER' FROM EMPLOYEE;

COMMIT;

 

 

데이터 잘 들어갔는지 확인

SELECT A.USERNAME, A.PASSWORD, A.ENABLED
    , B.USERNAME, B.AUTHORITY
FROM USERS A, AUTHORITIES B
WHERE A.USERNAME = B.USERNAME;

 

결과 화면4

 

추후 ADMIN 도 테스트하기 위해 데이터를 변경해놓아야함

더보기
AUTHORITIES 테이블

 

 

security-context.xml

</security:authentication-provider> 안에 있는 것 수정

			<!-- jdbc로 해야 db에 있는 걸로 가져올 수 있음 -->
			<!-- root-context.xml에 있음 -->
			<security:jdbc-user-service data-source-ref="dataSource"/>
			<!-- 비밀번호 암호화 -->
			<security:password-encoder ref="passwordEncoder"/>
			
<!-- 			<security:user-service> 사용자 설정 -->
<!-- 				<security:user name="member" password="{noop}1234" authorities="ROLE_MEMBER"/> -->
<!-- 				<security:user name="admin" password="{noop}1234" authorities="ROLE_MEMBER,ROLE_ADMIN"/> -->

<!-- 			</security:user-service> -->

 

</beans> 안에 추가

<!-- 비밀번호 암호화 처리글   -->
<bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>

 

 

LoginController.java

이름이 같아야 함

 

package kr.or.ddit.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class LoginController {
	
	//DI / IoC
	//passwordEncoder 객체는 security-context.xml의 bean에 등록되어 있음
	@Autowired
	PasswordEncoder passwordEncoder;
	
	@GetMapping("/login")
	public String loginForm(Model model) {
		
		String pwd = "java";
		
		String encodedPwd = this.passwordEncoder.encode(pwd);
		log.info("encodedPwd : " + encodedPwd);
		
		//forwarding : jsp
		// /views/ + loginForm + ".jsp";
		return "loginForm";
	}
}

 

결과 화면5

 

USERS 테이블에서 PASSWORD를 변경

 

결과 화면6-1

 

결과 화면6-2

 

 

 

 

 

EMPLOYEE 테이블 수정

 

추가한 비밀번호 변경, 전부 JAVA를 암호화한 값으로 넣음

 

EMPLOYEE_AUTH 테이블 설정1

 

EMPLOYEE_AUTH 테이블 설정2

 

EMPLOYEE_AUTH 테이블 설정2

 

 

데이터 삽입

INSERT INTO EMPLOYEE_AUTH(EMP_NO, AUTH)
SELECT EMP_NO, 'ROLE_MEMBER'
FROM EMPLOYEE;

COMMIT;

 

+ 하나의 데이터만 ROLE_ADMIN으로 수정해야함

 

 

security-context.xml

<security:authentication-manager> 변경

	<security:authentication-manager>
		<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
		<security:authentication-provider user-service-ref="customUserDetailsService"> <!-- 인증 제공자 -->
			<!-- 비밀번호 암호화 -->
			<security:password-encoder ref="passwordEncoder"/>
		</security:authentication-provider>

 

</beans> 안에 추가

<bean id="customUserDetailsService" class="kr.or.ddit.security.CustomUserDetailsService">
</bean>

 

 

CustomUserDetailsService.java

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 org.springframework.stereotype.Service;

import kr.or.ddit.mapper.EmployeeMapper;
import kr.or.ddit.vo.EmployeeVO;
import lombok.extern.slf4j.Slf4j;

/*
UserDetailsService : 스프링 시큐리티에서 제공해주고 있는
사용자 상세 정보를 갖고 있는 인터페이스
 */
@Slf4j
@Service
public class CustomUserDetailsService implements UserDetailsService {

	//EMPLOYEE 테이블을 위한 매퍼 인터페이스
	//DI(Dependency Injection) : 의존성 주입
	//IoC(Inversion of Control) : 제어의 역전
	@Autowired
	private EmployeeMapper employeeMapper;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//1) 사용자 정보를 검색
		//username : 로그인 시 입력 받은 회원의 아이디. <input type="text" name="username"
		log.info("CustomUserDetailsService->username : " + username);
		
		//1명이 로그인을 함
		EmployeeVO employeeVO = this.employeeMapper.detail(username);
		log.info("CustomUserDetailsService->employeeVO : " + employeeVO);
		
		//MVC에서는 Controller로 리턴하지 않고, CustomUser로 리턴함
		//CustomUser : 사용자 정의 유저 정보. extends User를 상속받고 있음
		//2) 스프링 시큐리티의 User 객체의 정보로 넣어줌 => 프링이가 이제부터 해당 유저를 관리
		//User : 스프링 시큐리에서 제공해주는 사용자 정보 클래스
		/*
		memberVO(우리) -> user(시큐리티)
		-----------------
		empNo        		-> username
		empPwd        		-> password
		enabled       		-> enabled
		employeeAuthVOList	-> authorities
		*/
		return employeeVO==null?null:new CustomUser(employeeVO);
	}

}

 

 

EmployeeMapper.java

package kr.or.ddit.security;

import kr.or.ddit.vo.EmployeeVO;

public interface EmployeeMapper {

	public EmployeeVO detail(String username);
	
}

 

 

employee2_SQL.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.EmployeeMapper">
	
	<resultMap type="employeeVO" id="employeeMap">
		<result property="empNo" column="EMP_NO"/>
		<result property="empName" column="EMP_NAME"/>
		<result property="empAddress" column="EMP_ADDRESS"/>
		<result property="empTelno" column="EMP_TELNO"/>
		<result property="empSalary" column="EMP_SALARY"/>
		<result property="filename" column="FILENAME"/>
		<result property="empPwd" column="EMP_PWD"/>
		<result property="enabled" column="ENABLED"/>
		<collection property="employeeAuthVOList" resultMap="employeeAuthMap"></collection>
	</resultMap>
	
	<resultMap type="employeeAuthVO" id="employeeAuthMap">
		<result property="empNo" column="EMP_NO"/>
		<result property="auth" column="AUTH"/>
	</resultMap>

	<select id="detail" parameterType="String" resultMap="employeeMap">
		SELECT A.EMP_NO, A.EMP_NAME, A.EMP_ADDRESS, A.EMP_TELNO, A.EMP_SALARY, A.FILENAME, A.EMP_PWD, A.ENABLED
		    , B.EMP_NO, B.AUTH
		FROM EMPLOYEE A, EMPLOYEE_AUTH B
		WHERE A.EMP_NO = B.EMP_NO
		AND A.EMP_NO = #{username}
	</select>
</mapper>

 

 

EmployeeVO.java

package kr.or.ddit.vo;

import java.util.List;

import javax.validation.Valid;

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.springframework.web.multipart.MultipartFile;

import lombok.Data;

@Data
public class EmployeeVO {
	@NotBlank(message = "직원 번호를 입력해주세요")
	private String empNo;
	
	@NotBlank(message = "직원 명을 입력해주세요")
	private String empName;
	
	@NotBlank(message = "주소를 입력해주세요")
	private String empAddress;
	
	@NotBlank(message = "연락처를 입력해주세요")
	private String empTelno;
	
	@Range(min=1,message="급여를 입력해주세요.")
	private int empSalary;

	
	private String filename;
	private String empPwd;
	private String enabled;
	
	
	@Valid
	private List<LicenseVO> licenseVOList;
	
	//중첩된 자바빈 컬렉션
	private List<EmployeeAuthVO> employeeAuthVOList;
	
	//EMPLOYEE : 증명사진 = 1 : 1
	private MultipartFile uploadFile;
}

 

 

EmployeeAuthVO.java

package kr.or.ddit.vo;

import lombok.Data;

@Data
public class EmployeeAuthVO {
	private String empNo;
	private String auth;
}

 

 

mybatisAlias.xml

</typeAliases> 안에 추가

<typeAlias type="kr.or.ddit.vo.EmployeeAuthVO" alias="employeeAuthVO"/>

 

 

CustomUser.java

CustomUser 세팅, Set<GrantedAuthority>로 값이 들어감

 

package kr.or.ddit.security;

import java.util.Collection;
import java.util.Set;
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.EmployeeVO;

//User : 스프링 시큐리티의 사용자 정보를 관리하는 사용자 최상위 클래스
public class CustomUser extends User {
	/* User 클래스의 프로퍼티
	private String password;
	private final String username;
	private final Set<GrantedAuthority> authorities;
	private final boolean accountNonExpired;
	private final boolean accountNonLocked;
	private final boolean credentialsNonExpired;
	private final boolean enabled;
	*/
	private EmployeeVO employeeVO;
	
	//User의 생성자를 처리해줌
	public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super(username, password, authorities);
	}

	public CustomUser(EmployeeVO employeeVO) {
		//사용자가 정의한 (select한) MemberVO 타입의 객체 memberVO를
		//스프링 시큐리티에서 제공해주고 있는 UsersDetails 타입으로 변환
		//회원정보를 보내줄테니 이제부터 프링이 너가 관리해줘
		super(employeeVO.getEmpNo(),employeeVO.getEmpPwd(),
			employeeVO.getEmployeeAuthVOList().stream() //stream : 쭉 나열
			.map(auth->new SimpleGrantedAuthority(auth.getAuth())) //객체 2개가 생성됨
			.collect(Collectors.toList())
				);
		this.employeeVO = employeeVO;
	}

	public EmployeeVO getEmployeeVO() {
		return employeeVO;
	}

	public void setEmployeeVO(EmployeeVO employeeVO) {
		this.employeeVO = employeeVO;
	}
}

 

결과 화면7

 

 

더보기

테이블 정보

MEMBER 테이블

  

MEMBER_AUTH 테이블

 

 

데이터 삽입

INSERT INTO MEMBER_AUTH(USER_ID,AUTH)
SELECT USER_ID,'ROLE_MEMBER'
FROM MEMBER;

COMMIT;

SELECT * FROM MEMBER_AUTH;

 

결과 화면8

 

SELECT A.USER_ID, A.USER_NAME, A.PASSWORD, A.REG_DATE, A.COIN, A.ENABLED
    , B.AUTH
FROM MEMBER A, MEMBER_AUTH B
WHERE A.USER_ID = B.USER_ID
AND A.USER_ID = 'b001';

 

결과 화면9 : 암호화한 비밀번호로 PASSWORD에 넣어야 함

 

 

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">

	<!-- CustomAccessDeniedHandler customAccessDenied = new CustomAccessDeniedHandler(); 와 같은 문장임 -->
	<bean id="customAccessDenied" 
		class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
	
	<bean id="customLoginSuccess" class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>
	
	<!-- 비밀번호 암호화 처리글   -->
	<bean id="passwordEncoder"
	class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
	
	<!-- 스프링 시큐리티의 UserDetailsService를 구현한 클래스를 빈으로 등록함 -->
	<bean id="customUserDetailsService2" class="kr.or.ddit.security.CustomUserDetailsService2">
	</bean>
	
	<security:http>
		<!-- URI 패턴으로 접근 제한을 설정함 -->
		<!-- URL을 가로챔 -->
		<!-- 누구나 접근 가능 -> 생략 가능 -->
		<security:intercept-url pattern="/board/list" access="permitAll"/> <!-- permitAll : 누구나 접근 가능 -->
		<security:intercept-url pattern="/board/register" access="hasRole('ROLE_MEMBER')" /> <!-- ROLE_MEMBER 권한을 가졌을 때 : 회원만 접근 -->
		<security:intercept-url pattern="/notice/list" access="permitAll" />
		<security:intercept-url pattern="/notice/register" access="hasRole('ROLE_ADMIN')" /> <!-- ROLE_ADMIN 권한을 가졌을 때 : 관리자만 접근 -->


		<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함
		사용자 정의 로그인 성공 처리자를 지정함
		/login : get방식 -> LoginController에서 매핑 -->
		<security:form-login login-page="/login" 
			authentication-success-handler-ref="customLoginSuccess"/>

		<!-- 등록한 사용자 정의 bean을 접근 거부 처리자로 지정함 -->
		<security:access-denied-handler ref="customAccessDenied"/>
		
		<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화(session.invalidate())함 
		/logout : post방식 요청URI -> form의 action="/logout"에서 사용 -->
		<security:logout logout-url="/logout" invalidate-session="true" />
		
	</security:http>
	
	<security:authentication-manager>
		<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
		<security:authentication-provider user-service-ref="customUserDetailsService2"> <!-- 인증 제공자 -->
			<!-- 비밀번호 암호화 -->
			<security:password-encoder ref="passwordEncoder"/>
		</security:authentication-provider>
		
	</security:authentication-manager>
</beans>

 

 

CustomUserDetailsService2.java

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 org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.MemberMapper;
import kr.or.ddit.vo.Member;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CustomUserDetailsService2 implements UserDetailsService {

	@Autowired
	private MemberMapper memberMapper;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		log.info("CustomUserDetailsService2 -> username : " + username);
		
		//select
		Member member =  this.memberMapper.detail(username);
		log.info("CustomUserDetailsService2->member : " + member);
		
		//User(스프링꺼)
		//CustomUser2(우리꺼)
		return member==null?null:new CustomUser2(member);
	}

}

 

 

MemberMapper.java

root-context에 Mapper 인터페이스 설정을 미리 해둠

package kr.or.ddit.mapper;

import kr.or.ddit.vo.Member;

public interface MemberMapper {
	public Member detail(String username);
}

 

 

member2_SQL.xml

받아온 username의 값이 들어가는 위치

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.MemberMapper">

	<resultMap type="member" id="memberMap">
		<result property="userId" column="USER_ID"/>
		<result property="userName" column="USER_NAME"/>
		<result property="password" column="PASSWORD"/>
		<result property="regDate" column="REG_DATE"/>
		<result property="coin" column="COIN"/>
		<result property="enabled" column="ENABLED"/>
		<collection property="memberAuthVOList" resultMap="memberAuthMap"></collection>
	</resultMap>
	
	<resultMap type="memberAuthVO" id="memberAuthMap">
		<result property="userId" column="USER_ID"/>
		<result property="auth" column="AUTH"/>
	</resultMap>
	
	<!-- 부모(MEMBER) 1 : 자식(MEMBER_AUTH) N = 1 : N -->
	<select id="detail" parameterType="String" resultMap="memberMap">
		SELECT A.USER_ID, A.USER_NAME, A.PASSWORD, A.REG_DATE, A.COIN, A.ENABLED
		    , B.AUTH
		FROM MEMBER A, MEMBER_AUTH B
		WHERE A.USER_ID = B.USER_ID
		AND A.USER_ID = #{username}
	</select>
</mapper>

 

 

Member.java

package kr.or.ddit.vo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;

import lombok.Data;

@Data
public class Member {
	@NotBlank
	private String userId;
	
	@NotBlank(message="사용자명을 입력해주세요.")
	@Size(max=3, message="최대 3글자까지만 작성해주세요.")
	private String userName;
	
	private String password = "1234";
	@DateTimeFormat(pattern="yyyy-MM-dd") private Date regDate;
	private int coin;
	private String enabled;
	
	//부모(MEMBER) 1 : 자식(MEMBER_AUTH) N = 1 : N
	private List<MemberAuthVO> memberAuthVOList;
}

 

 

MemberAuthVO.java

package kr.or.ddit.vo;

import lombok.Data;

@Data
public class MemberAuthVO {
	private String userId;
	private String auth;
}

 

 

mybatisAlias.xml
<typeAliases> 안에 추가

<typeAlias type="kr.or.ddit.vo.MemberAuthVO" alias="memberAuthVO"/>

 

 

CustomUser2.java

package kr.or.ddit.security;

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

import org.springframework.beans.factory.annotation.Autowired;
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.Member;

//사용자가 유저를 정의함
//memberVO(select결과)정보를 User(스프링 시큐리티에서 정의된 유저) 객체 정보에 연계하여 넣어줌
//CustomUser의 객체 = principal
public class CustomUser2 extends User {

	private Member member;
	
	public CustomUser2(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super(username, password, authorities);
	}

	//return member==null?null:new CumstomUser2(member);
	public CustomUser2(Member member) {
		super(member.getUserId(), member.getPassword(), 
				member.getMemberAuthVOList().stream()
				.map(auth->new SimpleGrantedAuthority(auth.getAuth()))
				.collect(Collectors.toList())
				);
		
		this.member = member;
	}

	public Member getMember() {
		return member;
	}

	public void setMember(Member member) {
		this.member = member;
	}
}

 

결과 화면10

 

결과 화면11

 

 

 

  • 이름 변경 (principal)

aside.jsp

principal 추가 및 설정 관련 수정

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
	<!-- Brand Logo -->
	<a href="index3.html" class="brand-link"> <img
		src="/resources/adminlte/dist/img/AdminLTELogo.png"
		alt="AdminLTE Logo" class="brand-image img-circle elevation-3"
		style="opacity: .8"> <span class="brand-text font-weight-light">AdminLTE
			3</span>
	</a>

	<!-- Sidebar -->
	<div class="sidebar">
		<!-- Sidebar user panel (optional) -->
		<!-- /// 로그인 안함 시작 /// -->
		<!-- isAnonymous() 는 로그인 안 했을 때 true -> 아래 코드 실행 -->
		<sec:authorize access="isAnonymous()"> <!-- 인가 : 권한 -->
			<div class="user-panel mt-3 pb-3 mb-3 d-flex">
				<div class="image">
					<img src="/resources/adminlte/dist/img/user2-160x160.jpg"
						class="img-circle elevation-2" alt="User Image">
				</div>
				<div class="info">
					<a href="#" class="d-block">Alexander Pierce</a>
				</div>
			</div>
		</sec:authorize>
		<!-- /// 로그인 안함 끝 /// -->
		
		<!-- /// 로그인 함 시작 /// -->
		<sec:authorize access="isAuthenticated()">
		
			<!-- principal : 사용자정보 객체
			var속성이 있으면 JSTL변수에 할당.
			var속성이 없으면 화면에 출력.-->
			<sec:authentication property="principal.member" var="member"/>
			<sec:authentication property="principal.member.memberAuthVOList" var="memberAuthVOList" />
			
			<c:forEach var="memberAuthVO" items="${memberAuthVOList}" varStatus="stat">
				<p>${memberAuthVO.auth}</p>
			</c:forEach>
			
			<div class="user-panel mt-3 pb-3 mb-3 d-flex">
				<div class="image">
					<img src="/resources/upload/mang6.jpg"
						class="img-circle elevation-2" alt="User Image">
				</div>
				<div class="info">
					<a href="#" class="d-block">${member.userName}님 환영합니다.</a>
					<form action="/logout" method="post"> <!-- 꼭 post여야함 -->
						<button type="submit" class="btn btn-block btn-secondary btn-xs">로그아웃</button>
						<sec:csrfInput/>
					</form>
				</div>
			</div>
		</sec:authorize>
		<!-- /// 로그인 함 끝 /// -->


		<!-- SidebarSearch Form -->
		<div class="form-inline">
			<div class="input-group" data-widget="sidebar-search">
				<input class="form-control form-control-sidebar" type="search"
					placeholder="Search" aria-label="Search">
				<div class="input-group-append">
					<button class="btn btn-sidebar">
						<i class="fas fa-search fa-fw"></i>
					</button>
				</div>
			</div>
		</div>

		<!-- Sidebar Menu -->
		<nav class="mt-2">
			<ul class="nav nav-pills nav-sidebar flex-column"
				data-widget="treeview" role="menu" data-accordion="false">
				<!-- Add icons to the links using the .nav-icon class
               with font-awesome or any other icon font library -->
				<li class="nav-item menu-open"><a href="#"
					class="nav-link active"> <i
						class="nav-icon fas fa-tachometer-alt"></i>
						<p>
							Dashboard <i class="right fas fa-angle-left"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="./index.html"
							class="nav-link active"> <i class="far fa-circle nav-icon"></i>
								<p>Dashboard v1</p>
						</a></li>
						<li class="nav-item"><a href="./index2.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>Dashboard v2</p>
						</a></li>
						<li class="nav-item"><a href="./index3.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>Dashboard v3</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="pages/widgets.html"
					class="nav-link"> <i class="nav-icon fas fa-th"></i>
						<p>
							Widgets <span class="right badge badge-danger">New</span>
						</p>
				</a></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-copy"></i>
						<p>
							Layout Options <i class="fas fa-angle-left right"></i> <span
								class="badge badge-info right">6</span>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/layout/top-nav.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Top Navigation</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/layout/top-nav-sidebar.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Top Navigation + Sidebar</p>
						</a></li>
						<li class="nav-item"><a href="pages/layout/boxed.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Boxed</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/layout/fixed-sidebar.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Fixed Sidebar</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/layout/fixed-sidebar-custom.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>
									Fixed Sidebar <small>+ Custom Area</small>
								</p>
						</a></li>
						<li class="nav-item"><a href="pages/layout/fixed-topnav.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Fixed Navbar</p>
						</a></li>
						<li class="nav-item"><a href="pages/layout/fixed-footer.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Fixed Footer</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/layout/collapsed-sidebar.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>Collapsed Sidebar</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-chart-pie"></i>
						<p>
							Charts <i class="right fas fa-angle-left"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/charts/chartjs.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>ChartJS</p>
						</a></li>
						<li class="nav-item"><a href="pages/charts/flot.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Flot</p>
						</a></li>
						<li class="nav-item"><a href="pages/charts/inline.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Inline</p>
						</a></li>
						<li class="nav-item"><a href="pages/charts/uplot.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>uPlot</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-tree"></i>
						<p>
							UI Elements <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/UI/general.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>General</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/icons.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Icons</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/buttons.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Buttons</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/sliders.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Sliders</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/modals.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Modals & Alerts</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/navbar.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Navbar & Tabs</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/timeline.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Timeline</p>
						</a></li>
						<li class="nav-item"><a href="pages/UI/ribbons.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Ribbons</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-edit"></i>
						<p>
							Forms <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/forms/general.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>General Elements</p>
						</a></li>
						<li class="nav-item"><a href="pages/forms/advanced.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Advanced Elements</p>
						</a></li>
						<li class="nav-item"><a href="pages/forms/editors.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Editors</p>
						</a></li>
						<li class="nav-item"><a href="pages/forms/validation.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Validation</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-table"></i>
						<p>
							Tables <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/tables/simple.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Simple Tables</p>
						</a></li>
						<li class="nav-item"><a href="pages/tables/data.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>DataTables</p>
						</a></li>
						<li class="nav-item"><a href="pages/tables/jsgrid.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>jsGrid</p>
						</a></li>
					</ul></li>
				<li class="nav-header">EXAMPLES</li>
				<li class="nav-item"><a href="pages/calendar.html"
					class="nav-link"> <i class="nav-icon far fa-calendar-alt"></i>
						<p>
							Calendar <span class="badge badge-info right">2</span>
						</p>
				</a></li>
				<li class="nav-item"><a href="pages/gallery.html"
					class="nav-link"> <i class="nav-icon far fa-image"></i>
						<p>Gallery</p>
				</a></li>
				<li class="nav-item"><a href="pages/kanban.html"
					class="nav-link"> <i class="nav-icon fas fa-columns"></i>
						<p>Kanban Board</p>
				</a></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon far fa-envelope"></i>
						<p>
							Mailbox <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/mailbox/mailbox.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Inbox</p>
						</a></li>
						<li class="nav-item"><a href="pages/mailbox/compose.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Compose</p>
						</a></li>
						<li class="nav-item"><a href="pages/mailbox/read-mail.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Read</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-book"></i>
						<p>
							Pages <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/examples/invoice.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Invoice</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/profile.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Profile</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/e-commerce.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>E-commerce</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/projects.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Projects</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/examples/project-add.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Project Add</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/examples/project-edit.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Project Edit</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/examples/project-detail.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Project Detail</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/contacts.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Contacts</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/faq.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>FAQ</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/contact-us.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Contact us</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon far fa-plus-square"></i>
						<p>
							Extras <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="#" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>
									Login & Register v1 <i class="fas fa-angle-left right"></i>
								</p>
						</a>
							<ul class="nav nav-treeview">
								<li class="nav-item"><a href="pages/examples/login.html"
									class="nav-link"> <i class="far fa-circle nav-icon"></i>
										<p>Login v1</p>
								</a></li>
								<li class="nav-item"><a href="pages/examples/register.html"
									class="nav-link"> <i class="far fa-circle nav-icon"></i>
										<p>Register v1</p>
								</a></li>
								<li class="nav-item"><a
									href="pages/examples/forgot-password.html" class="nav-link">
										<i class="far fa-circle nav-icon"></i>
										<p>Forgot Password v1</p>
								</a></li>
								<li class="nav-item"><a
									href="pages/examples/recover-password.html" class="nav-link">
										<i class="far fa-circle nav-icon"></i>
										<p>Recover Password v1</p>
								</a></li>
							</ul></li>
						<li class="nav-item"><a href="#" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>
									Login & Register v2 <i class="fas fa-angle-left right"></i>
								</p>
						</a>
							<ul class="nav nav-treeview">
								<li class="nav-item"><a href="pages/examples/login-v2.html"
									class="nav-link"> <i class="far fa-circle nav-icon"></i>
										<p>Login v2</p>
								</a></li>
								<li class="nav-item"><a
									href="pages/examples/register-v2.html" class="nav-link"> <i
										class="far fa-circle nav-icon"></i>
										<p>Register v2</p>
								</a></li>
								<li class="nav-item"><a
									href="pages/examples/forgot-password-v2.html" class="nav-link">
										<i class="far fa-circle nav-icon"></i>
										<p>Forgot Password v2</p>
								</a></li>
								<li class="nav-item"><a
									href="pages/examples/recover-password-v2.html" class="nav-link">
										<i class="far fa-circle nav-icon"></i>
										<p>Recover Password v2</p>
								</a></li>
							</ul></li>
						<li class="nav-item"><a href="pages/examples/lockscreen.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Lockscreen</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/examples/legacy-user-menu.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>Legacy User Menu</p>
						</a></li>
						<li class="nav-item"><a
							href="pages/examples/language-menu.html" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Language Menu</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/404.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Error 404</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/500.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Error 500</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/pace.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Pace</p>
						</a></li>
						<li class="nav-item"><a href="pages/examples/blank.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Blank Page</p>
						</a></li>
						<li class="nav-item"><a href="starter.html" class="nav-link">
								<i class="far fa-circle nav-icon"></i>
								<p>Starter Page</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-search"></i>
						<p>
							Search <i class="fas fa-angle-left right"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="pages/search/simple.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Simple Search</p>
						</a></li>
						<li class="nav-item"><a href="pages/search/enhanced.html"
							class="nav-link"> <i class="far fa-circle nav-icon"></i>
								<p>Enhanced</p>
						</a></li>
					</ul></li>
				<li class="nav-header">MISCELLANEOUS</li>
				<li class="nav-item"><a href="iframe.html" class="nav-link">
						<i class="nav-icon fas fa-ellipsis-h"></i>
						<p>Tabbed IFrame Plugin</p>
				</a></li>
				<li class="nav-item"><a href="https://adminlte.io/docs/3.1/"
					class="nav-link"> <i class="nav-icon fas fa-file"></i>
						<p>Documentation</p>
				</a></li>
				<li class="nav-header">MULTI LEVEL EXAMPLE</li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="fas fa-circle nav-icon"></i>
						<p>Level 1</p>
				</a></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon fas fa-circle"></i>
						<p>
							Level 1 <i class="right fas fa-angle-left"></i>
						</p>
				</a>
					<ul class="nav nav-treeview">
						<li class="nav-item"><a href="#" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Level 2</p>
						</a></li>
						<li class="nav-item"><a href="#" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>
									Level 2 <i class="right fas fa-angle-left"></i>
								</p>
						</a>
							<ul class="nav nav-treeview">
								<li class="nav-item"><a href="#" class="nav-link"> <i
										class="far fa-dot-circle nav-icon"></i>
										<p>Level 3</p>
								</a></li>
								<li class="nav-item"><a href="#" class="nav-link"> <i
										class="far fa-dot-circle nav-icon"></i>
										<p>Level 3</p>
								</a></li>
								<li class="nav-item"><a href="#" class="nav-link"> <i
										class="far fa-dot-circle nav-icon"></i>
										<p>Level 3</p>
								</a></li>
							</ul></li>
						<li class="nav-item"><a href="#" class="nav-link"> <i
								class="far fa-circle nav-icon"></i>
								<p>Level 2</p>
						</a></li>
					</ul></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="fas fa-circle nav-icon"></i>
						<p>Level 1</p>
				</a></li>
				<li class="nav-header">LABELS</li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon far fa-circle text-danger"></i>
						<p class="text">Important</p>
				</a></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon far fa-circle text-warning"></i>
						<p>Warning</p>
				</a></li>
				<li class="nav-item"><a href="#" class="nav-link"> <i
						class="nav-icon far fa-circle text-info"></i>
						<p>Informational</p>
				</a></li>
			</ul>
		</nav>
		<!-- /.sidebar-menu -->
	</div>
	<!-- /.sidebar -->
</aside>

 

결과 화면12

 

 

반응형