- 오라클 사용
- XML 설정 사용
- JDBC를 위한 DriverManaberDataSource 사용
1. 권한 처리를 위한 테이블 생성
CREATE TABLE authorities(
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)
);
CREATE UNIQUE INDEX ix_auth_username on authorities(username, authority);
INSERT INTO USERS (username, password) VALUES('user00', 'pw00');
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_MANAGER');
INSERT INTO authorities (username, authority) VALUES('admin00', 'ROLE_ADMIN');
COMMIT;
2. JDBC연결을 위한 Bean생성(DriverManaberDataSource사용)
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="scott" />
<property name="password" value="tiger" />
</bean>
</beans>
3. 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">
<!-- 1. 로그인/에러 처리를 위한 빈 설정(4에서 등록)-->
<bean id="customLoginSuccess" class="org.zerock.security.CustomLoginSuccessHandler"></bean>
<bean id="customAccessDenied" class="org.zerock.security.CustomAccessDeniedHandler"></bean>
<!-- 2. password encoder를 위한 빈 설정 -->
<bean id="customPasswordEncoder" class="org.zerock.security.CustomNoOpPasswordEncoder"></bean>
<security:http auto-config="true">
<!-- 3. 각 url 패턴에 따른 access 조건 설정 -->
<security:intercept-url pattern="/sample/all" access="permitAll"></security:intercept-url>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"></security:intercept-url>
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')"></security:intercept-url>
<!-- 4. 로그인 안되어 있을 경우 로그인 페이지 이동 설정 및 로그인 성공/실패 Bean 등록(1번에서 만듦) -->
<security:form-login login-page="/customLogin" authentication-success-handler-ref="customLoginSuccess" />
<security:access-denied-handler ref="customAccessDenied" />
</security:http>
<security:authentication-manager
alias="authenticationManager">
<security:authentication-provider>
<!-- 5-1. jdbc를 위한 dataSource빈 등록(root-context.xml에서 만들었음) -->
<!-- 5-2. DB에서 사용자와 권한 정보를 가져오는 쿼리 작성 -->
<security:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="SELECT USERNAME, PASSWORD, ENABLED FROM USERS WHERE USERNAME=?"
authorities-by-username-query="SELECT USERNAME, AUTHORITY FROM AUTHORITIES WHERE USERNAME=?" />
<!-- 6. password Encoder 등록(2에서 만듦) -->
<security:password-encoder ref="customPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
</beans>
1. 로그인 성공/ 에러 처리를 위한 Bean 생성 - 각 class는 만들어야함.
2. password Encoder를 위한 Bean등록 - 각 class는 만들어야하며(PasswordEncoder 구현), Security5부터 필수임.
3. url패턴에 따라 권한 조건 설정
4. 1번에서 생성한 로그인 성공/에러 처리를 위한 Bean등록
5. jdbc를 위한 dataSource등록 및 사용자/권한 정보를 가져오기 위한 쿼리 등록
6. 2에서 생성한 password Encoder를 등록
4. 로그인 성공/에러를 위한 클래스
로그인 거부 처리 : CustomAccessDeniedHandler.java
package org.zerock.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.java.Log;
@Log
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("Access Denied Handler");
log.info("redirect....");
response.sendRedirect("/security/accessError");
}
}
로그인 성공처리 CustomLoginSuccessHandler.java
package org.zerock.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.web.authentication.AuthenticationSuccessHandler;
import lombok.extern.java.Log;
@Log
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication auth) throws IOException, ServletException {
log.info("Login Success");
List<String> roleNames = new ArrayList<>();
auth.getAuthorities().forEach(authority -> {
roleNames.add(authority.getAuthority());
});
log.info("ROLE NAME : " + roleNames);
if(roleNames.contains("ROLE_ADMIN")) {
response.sendRedirect("/security/sample/admin");
return;
}
if(roleNames.contains("ROLE_MEMBER")) {
response.sendRedirect("/security/sample/member");
return;
}
response.sendRedirect("/");
}
}
5. PasswordEncoder 클래스
CustomNoOpPasswordEncoder.java
아래 클래스는 rawPassword 그냥 사용.
package org.zerock.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
public class CustomNoOpPasswordEncoder implements PasswordEncoder {
Logger log = LoggerFactory.getLogger(CustomNoOpPasswordEncoder.class);
@Override
public String encode(CharSequence rawPassword) {
log.warn("before encode : " + rawPassword);
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
log.warn("rawPass : " + rawPassword + " : " + encodedPassword);
return rawPassword.toString().equals(encodedPassword);
}
}
6. 기타 jsp파일들
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Custom Login Page</h1>
<form method='post' action='login'>
<div>
<input type='text' name='username' value='admin'>
</div>
<div>
<input type='password' name='password' value='admin'>
</div>
<div>
<input type='submit'>
</div>
<input type='hidden' name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
</body>
</html>
input에 "${_csrf.parameterName}"'과 "${_csrf.token}"필요.(csrf공격 때문)
'Spring' 카테고리의 다른 글
| Spring Security - JWT이란? (0) | 2020.07.13 |
|---|---|
| Spring - 의존성주입 방법의 비교(생성자 주입, Setter주입, field주입) (0) | 2020.06.11 |
| SpringSecurity - 서블릿 기반 구조 (0) | 2020.05.12 |
| Spring - ServletContext와 RootContext (0) | 2020.05.08 |
| Spring - 관점 지향 프로그래밍(AOP) (0) | 2020.05.05 |