Spring 실습 18일차(시큐리티)
접근 거부
시큐리티 패키지와 CustomAccessDeniedHandler 클래스를 만들어준다.
package kr.or.ddit.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("handle");
// DB 작업
// 로그 작업
// 메세지 발송
response.sendRedirect("/accessError");
/*
공지사항 등록 화면(/notice/register)은
일반회원(member/java)이 접근할 수 없는 페이지이고,
관리자(admin/java)만 접근 가능하므로..
지정된 접근 거부 처리자(CustomAccessDeniedHander)에서
접근 거부 처리 페이지(/accessError)로 리다이렉트 시킴
*/
}
}
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="customAccessDeniedHandler"
class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
<security:http>
<!-- <security:csrf disabled="true"/> -->
<!-- URI 패턴으로 접근 제한을 설정함 -->
<security:intercept-url pattern="/board/list" access="permitAll"/> <!-- access="permitAll" : 누구나 접근가능 -->
<security:intercept-url pattern="/board/register" access="hasRole('ROLE_MEMBER')"/> <!-- 회원만 접근가능 -->
<security:intercept-url pattern="/notice/list" access="permitAll"/> <!-- access="permitAll" : 누구나 접근가능 -->
<security:intercept-url pattern="/notice/register" access="hasRole('ROLE_ADMIN')"/> <!-- 관리자만 접근가능 -->
<!-- 폼 기반 인증 기능을 사용 -->
<security:form-login />
<!-- 접근 거부 처리자의 URI 지정 -->
<!-- <security:access-denied-handler error-page="/accessError"/> -->
<!-- 등록한 사용자 정의 bean을 접근 거부 처리자로 지정함 -->
<security:access-denied-handler ref="customAccessDeniedHandler"/>
</security:http>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정-->
<!-- 스프링 시큐리니티 5부터 기본적으로 PasswordEncoder를 지정해야 하는데,
그 이유는 사용자 테이블(USERS)에 비밀번호를 암호화하여 저장해야 하므로..
우리는 우선 비밀번호를 암호화 처리 하지 않았으므로
암호화 하지 않는 PasswordEncoder를 직접 구현하여 지정하기로 함
noop : no option password
-->
<!-- authentication : 인증 (로그인) -->
<security:authentication-manager>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
<security:authentication-provider>
<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>
</security:authentication-provider>
</security:authentication-manager>
</beans>
<bean id="customAccessDeniedHandler"
class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
class의 위치에 있는 class파일을 bean으로 등록해 메모리에 올림
notice / register는 admin권한이 있는 아이디만 접근이 가능하다.
여기까지는 어제 했던 방식과 크게 다르지 않다.
로그인 화면
<!-- 폼 기반 인증 기능을 사용 -->
<!-- <security:form-login /> -->
<security:form-login login-page="/login" />
이전에 만들어놓은 form-login은 주석처리를 해준 뒤 위 코드를 작성해준다
시큐리티의 로그인이 필요한 경우 /login 경로를 호출한다
controller패키지에 위 호출을 받아줄 LoginController를 만들어준다.
package kr.or.ddit.controller;
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 {
@GetMapping("/login")
public String loginForm(Model model) {
log.info("loginForm");
return "loginForm";
}
}
views에 loginForm.jsp를 만들어준다.
<%@ 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"%>
<center>
<div class="login-box">
<div class="card center">
<div class="card-body login-card-body">
<p class="login-box-msg">Sign in to start your session</p>
<form action="/login" method="post">
<div class="input-group mb-3">
<input type="text" name="userName" id="userName" class="form-control" placeholder="아이디">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope"></span>
</div>
</div>
</div>
<div class="input-group mb-3">
<input type="password" name="password" id="password" class="form-control" placeholder="비밀번호">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-8">
<div class="icheck-primary">
<input type="checkbox" id="remember"> <label
for="remember"> Remember Me </label>
</div>
</div>
<div class="col-4">
<button type="submit" class="btn btn-primary btn-block">Sign
In</button>
</div>
</div>
<!-- csrf : Cross Site Request Forgery -->
<sec:csrfInput />
</form>
</div>
</div>
</div>
</center>
<center>태그는 안에 들어있는 코드들을 화면 가운데로 위치시킨다.
위 jsp코드에서 중요한 점은 각 id와 password의 name값이 username, password로 작성되어야 한다는 점이다.
또한 sec태그를 사용한 코드가 있어야 post방식으로 처리가 가능하다. 자세한 내용은 후술
로그인 성공 처리
security-context.xml에 로그인 성공을 위한 클래스를 bean으로 등록하겠다는 코드를 추가해주고
<bean id="customLoginSuccess"
class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>
security 패키지에 위 경로의 이름대로 CustomLoginSuccessHandler 클래스를 만들어준다.
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 customUser = (User) auth.getPrincipal();
// 사용자의 Id 리턴
log.info("username : " + customUser.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);
}
}
로그아웃
security-context.xml에 따로 추가를 해주어야 한다. /logout페이지가 따로 필요하진 않음
<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화함
/logout : post방식, 요청 URI = form의 action="logout" -->
<security:logout logout-url="/logout" invalidate-session="true" />
우선 로그아웃을 하려면 로그인이 되어있어야 하고, 로그인을 했는지 확인이 되어야 하기 때문에 tiles폴더의 aside에서
이 부분이 로그인 하면 로그인한 회원으로 변하도록 만들어보겠다.
우선 하단의 코드를 aside에 덮어씌워준다.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<!-- Sidebar user panel (optional) -->
<!-- /// 로그인 안 함(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()">
<%-- <sec:authentication property="principal" /> --%>
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="image">
<img src="/resources/upload/2024/05/14/7fc538d6-999e-4067-a02e-aa4552495802_A007.jpg" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">개똥이님 환영합니다.</a>
<form action="/logout" method="post">
<button type="submit" class="btn btn-block btn-secondary btn-xs">로그아웃</button>
<sec:csrfInput />
</form>
</div>
</div>
</sec:authorize>
<!-- /// 로그인 함 끝 /// -->
로그인에 성공했다면 아래 코드 // 로그인 함 // 부분이 실행되고
로그아웃을 할 시 로그인 창으로 넘어가며 // 로그인 안 함 // 부분이 실행된다.
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)
);
INSERT INTO USERS(USERNAME, PASSWORD)
SELECT EMP_NO, 'java' FROM EMPLOYEE;
INSERT INTO AUTHORITIES(USERNAME, AUTHORITY)
SELECT EMP_NO, 'ROLE_MAMBER' FROM EMPLOYEE;
SELECT A.USERNAME, A.PASSWORD, A.ENABLED, B.USERNAME, B.AUTHORITY
FROM USERS A, AUTHORITIES B
WHERE A.USERNAME = B.USERNAME;
username이 id, password가 비밀번호로 작동.
authority가 권한으로써 작동하도록 만들어야 한다.
security-context.xml 수정
<!-- 비밀번호 암호화 처리기를 빈으로 등록 -->
<bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
<!-- authentication : 인증 (로그인) -->
<security:authentication-manager>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
<security:authentication-provider>
<!-- 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> -->
</security:authentication-provider>
</security:authentication-manager>
이전에 작성한 security:user-service를 주석처리 하고 대신 아래 코드로 변경되었다.
<!-- root-context.xml에 있음 -->
<security:jdbc-user-service data-source-ref="dataSource" />
<!-- 비밀번호 암호화 -->
<security:password-encoder ref="passwordEncoder"/>
위 코드는 데이터베이스의 비밀번호인 java를 암호화 하겠다는 코드이다.
LoginController 수정
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) {
log.info("loginForm");
String pwd = "java";
String encodePwd = this.passwordEncoder.encode(pwd);
log.info("encodePwd : " + encodePwd);
return "loginForm";
}
}
PasswordEncoder란?
Spring Security에서는 비밀번호를 안전하게 저장할 수 있도록
비밀번호의 단방향 암호화를 지원하는 PasswordEncoder 인터페이스와 구현체들을 제공
저 암호화된 비밀번호를 데이터베이스에 넣어준다
그 다음 AUTHORITIES 테이블의 아이디 중 하나에 ROLE_ADMIN을 부여해준 뒤 로그인을 해보자
비밀번호는 암호화했지만 java로 로그인이 가능하다.
로그인에 성공하여 왼쪽 Alexander Pierce님이 사라지고 개똥이님이 표기된다
EMPLOYEE
이번에는 employee테이블의 정보로 로그인을 시도해보려 한다.
미리 만들어놓았던 employee 테이블에 emp_pwd(비밀번호)와 enabled(탈퇴여부, 기본값 = '1'(문자열))를 추가해준다.
비밀번호에 아까 암호화한 java를 넣어주고 다시 설정에 들어가 NotNull 설정을 해주자
(데이터가 없는 상태에서 NotNull 설정하면 적용되지 않는다.)
그리고 EMPLOYEE_AUTH 테이블을 만들어준다.
EMP_NO는 외래키로 등록해야 하므로 EMPLOYEE테이블의 EMP_NO와 데이터 유형과 크기가 같아야 한다.
위 설정까지 마쳐주자
CREATE EMPLOYEE_AUTH(
EMP_NO VARCHAR2(6),
AUTH VARCHAR2(100),
CONSTRAINT PK_EMPLOYEE_AUTH PRIMARY KEY(EMP_NO, AUTH),
CONSTRAINT FK_EMPLOYEE_AUTH FOREIGN KEY(EMP_NO)
REFERENCES EMPLOYEE(EMP_NO)
)
CREATE문을 작성하면 이렇게 될 것이다.
INSERT INTO EMPLOYEE_AUTH(EMP_NO, AUTH)
SELECT EMP_NO, 'ROLE_MEMBER'
FROM EMPLOYEE;
위 코드까지 실행해주면 EMP_NO당 권한이 부여된다.
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 = 'A004';
SELECT한 결과를 시큐리티에 넘겨주자
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="customAccessDeniedHandler"
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>
<bean id="customUserDetailsService"
class="org.springframework.security.CustomUserDetailsService"></bean>
<security:http>
<!-- <security:csrf disabled="true"/> -->
<!-- URI 패턴으로 접근 제한을 설정함 -->
<security:intercept-url pattern="/board/list"
access="permitAll" /> <!-- access="permitAll" : 누구나 접근가능 -->
<security:intercept-url
pattern="/board/register" access="hasRole('ROLE_MEMBER')" /> <!-- 회원만 접근가능 -->
<security:intercept-url pattern="/notice/list"
access="permitAll" /> <!-- access="permitAll" : 누구나 접근가능 -->
<security:intercept-url
pattern="/notice/register" access="hasRole('ROLE_ADMIN')" /> <!-- 관리자만 접근가능 -->
<!-- 폼 기반 인증 기능을 사용 -->
<!-- <security:form-login /> -->
<security:form-login login-page="/login"
authentication-success-handler-ref="customLoginSuccess" />
<!-- 로그아웃 처리를 위한 URI를 지정하고, 로그아웃한 후에 세션을 무효화함 /logout : post방식, 요청 URI
= form의 action="logout" -->
<security:logout logout-url="/logout"
invalidate-session="true" />
<!-- 접근 거부 처리자의 URI 지정 -->
<!-- <security:access-denied-handler error-page="/accessError"/> -->
<!-- 등록한 사용자 정의 bean을 접근 거부 처리자로 지정함 -->
<security:access-denied-handler
ref="customAccessDeniedHandler" />
</security:http>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정 -->
<!-- 스프링 시큐리니티 5부터 기본적으로 PasswordEncoder를 지정해야 하는데, 그 이유는 사용자 테이블(USERS)에
비밀번호를 암호화하여 저장해야 하므로.. 우리는 우선 비밀번호를 암호화 처리 하지 않았으므로 암호화 하지 않는 PasswordEncoder를
직접 구현하여 지정하기로 함 noop : no option password -->
<!-- authentication : 인증 (로그인) -->
<security:authentication-manager>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
<security:authentication-provider
user-service-ref="customUserDetailsService">
<!-- 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> -->
</security:authentication-provider>
</security:authentication-manager>
</beans>
변경된 부분은
<bean id="customUserDetailsService"
class="org.springframework.security.CustomUserDetailsService"></bean>
<!-- authentication : 인증 (로그인) -->
<security:authentication-manager>
<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정함 -->
<security:authentication-provider
user-service-ref="customUserDetailsService">
<!-- 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> -->
</security:authentication-provider>
</security:authentication-manager>
customerUserDetailsService라는 클래스를 bean으로 등록한다.라는 코드를 작성해줬다.
위 코드가 최종 프로젝트까지 쓸 최종 security-context.xml일 것이다.
security 패키지에 CustomUserDetailsService 클래스를 만들어준다.
interface의 add를 눌러 UserDetailsService interface를 검색해 추가하고 만들어야한다
UserDetailsService란?
Spring Security에서 사용자의 정보를 담는 인터페이스이다.
package kr.or.ddit.security;
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 lombok.extern.slf4j.Slf4j;
/*
UserDetailsService : 스프링 시큐리티에서 제공해주고 있는
사용자 상세 정보를 갖고 있는 인터페이스
*/
@Slf4j
@Service
public class CustomUserDetailsService implements UserDetailsService {
//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);
return null;
}
}
아마 EmployeeMapper를 만든 적이 없을 것이니 Mapper 패키지에 만들어주자
package kr.or.ddit.mapper;
import kr.or.ddit.vo.EmployeeVO;
public interface EmployeeMapper {
public EmployeeVO detail(String username);
}
employee2_SQL.xml을 만들고 namespace를 mapper의 경로대로 적어준다
<?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>
SQL을 JOIN했기 때문에 resultMap으로 사용해야 한다.
위 대로 SQL문을 사용하려면 EmployeeVO와 EmployeeAuthVO를 추가로 작성해야한다.
private String empPwd;
private String enabled;
// 중첩된 자바빈
private List<EmployeeAuthVO> employeeAuthVOList;
package kr.or.ddit.vo;
import lombok.Data;
@Data
public class EmployeeAuthVO {
private String empNo;
private String auth;
}
이제 employee테이블에 있는 아이디 중 ADMIN속성이 있는 아이디로 로그인을 시도해보자
나는 A004가 두 권한을 가지고 있다.
비밀번호의 경우 암호화를 했지만 기본적으로 java이기 때문에 그대로 사용하면 된다.
위 CustomUserDetailsService에서 데이터를 처리한 후 return값이 null이기 때문에 다시 로그인 화면으로 돌아오는것이 정상적이다.
일단은 로그인이 성공한 것
<sec:csrfInput/>
<!-- csrf : Cross Site Request Forgery -->
<sec:csrfInput/>
시큐리티를 적용하고 있을 때 전송 방식은 GET방식밖에 사용할 수 없다. 나머지(POST, PUT ... )등을 사용하기 위해는 토큰 설정을 해주어야 하는데, 위 코드가 그 역할을 해주고 있다.
자동으로 설정해주기 때문에 다른 코드 필요없이 한줄로 사용 가능하다.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
위 JSTL이 있어야 sec태그를 사용할 수 있다.
18일차 종료