반응형
Notice
Recent Posts
Recent Comments
Link
불로구
[SpringFramework] - SpringSecurity를 이용한 로그인 설정 본문
반응형
스프링 시큐리티란?
- 스프링 기반의 어플리케이션의 보안( = 인증, 권한)을 담당하는 F/W
- 스프링 시큐리티를 통해 세션체크와 리다이렉트를 할 수 있다.
- 스프링 시큐리티는 Filter 기반으로 동작하기 때문에 Spring MVC와 분리되어 관리 및 동작
- 3.2버전 부터는 xml로 설정하지 않고 자바 bean 설정으로 가능
보안 용어
- 접근 주체(Principal) : 보호된 대상에 접근하는 유저
- 인증(Authenticate) : 현재 유저가 누구인지 확인 , 애플리케이션의 작업을 수행할 수 있는 주체임을 증명
- 인가(Authorize) : 현재 유저가 어떤 서비스, 페이지에 접근할 수 있는 권한이 있는지 검삭
- 권한 : 인증된 주체가 애플리케이션의 동작을 수행할 수 있도록 허락되어 있는지를 검사
- 권한 승인이 필요한 부분으로 접근하려면 인증 과정을 통해 주체가 증명 되어야만 한다.
- 권한 부여에도 두가지 영역이 존재하는데 웹 요청 권한, 메소드 호출 및 도메인 인스턴스에 대한 접근 권한 부여
인증 방법
- 스프링 시큐리티는 쿠키-세션 방식을 사용한다.
- 로그인 시도 -> AuthenticationFilter에서 user DB로 접근 -> 유효한 사용자면 SESSION 생성 -> SecurityContextHolder 세션 저장소에 저장 -> 유저에게 session ID와 응답 전달 -> 이후 요청시 요청쿠키에서 JSESSIONID를 검증 후 유효 시 세션ID로 바뀜
Spring Security의 Filter
- SecurityContextPersistenceFilter : SecurityContextRepository에서 SecurityContext를 가져오거나 저장하는 역할
- LogoutFilter : 로그아웃 처리
- (UsernamePassword)AuthenticationFilter : (아이디 비밀번호의 form 기반 인증) , 설정된 로그인 url로 오는 요청 감시, 인증처리
- AuthenticationManager로 인증
- 인증 성공 시, 얻은 Authentication 객체를 SecurityContext에 저장 후 AuthenticationSuccessHandler 실행
- 인증 실패 시, AuthenticationFailureHandler 실행
- DefaultLoginPageGeneratingFilter : 인증을 위한 로그인 폼 URL을 감시
- BasicAuthenticationFilter : HTTP 기본 인증 헤더를 감시하여 처리
- RequestCacheAwareFilter : 로그인 성공 후, 원래 요청 정보를 재구성하기 위해 사용
- AnonymousAuthenticationFilter : 이 필터가 호출되는 시정까지 사용자 정보가 인증되지 않았다면 인증 토큰에 사용자가 익명 사용자로 나타남
- SessionManagementFilter : 인증된 사용자와 관련된 모든 세션 추적
- FilterSecurityInterceptor : AccessDecisionManager로 권한부여 처리를 위임함으로써 접근 제어 결정을 쉽게 해줌
Authentication
- 모든 접근 주체는 Authentication를 생성한다.
- 생성된 Authentication은 SecurityContext에 보관되고 사용됨.
- 즉, 시큐리티 세션들은 내부 메모리에 쌓고 꺼내 쓰는 것
- Authentication 인터페이스
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); // Authentication 저장소에 의해 인증된 사용자의 권한 목록
Object getCredentials(); // 주로 비밀번호
Object getDetails(); // 사용자 상세정보
Object getPrincipal(); // 주로
ID boolean isAuthenticated(); //인증 여부
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
pom.xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
// 버전은 상황에 맞게
security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-4.3.xsd">
<!-- url 검사 -->
<http auto-config="true" use-expressions="true"> // use-expressions=true -> <intercept-url>의 access 속성에 표현식 사용 , false이면 access="USER"로 값을 사용해야 함
<intercept-url pattern="/login/**" access="permitAll" />
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" /> // <intercept-url> 요소는 url에 대한 access 속성의 권한 요구
<intercept-url pattern="/**" access="permitAll" /> // 여러개 사용 시 순서대로 매칭되어 사용 됨 , 가장 특수한 경우를 위쪽에 놓고 일반적인 것은 아래에 작성
<!-- <security:form-login /> -->
<form-login login-page="/login/loginForm.do" // 로그인을 위해서 폼을 사용 , 로그인처리 기본 URL은 "/login"
default-target-url = "/home.do" //로그인 후 기본으로 보여 질 페이지 지정
authentication-failure-url="/login/loginForm.do?error" //로그인 실패 시 보여질 체이지 지정 , 로그인 페이지 다시 보여 줌
username-parameter="id" //로그인 폼에 아이디 입력 필드에 사용될 name , 기본값 : username
password-parameter="password" /> //로그인 폼에 비밀번호 입력 필드에 사용 될 name, 기본 값 : password
<logout logout-url="/logout" //로그아웃 url 제공, 기본은 "/logout"
logout-success-url="/home.do" />
// <csrf disabled="false"/>라는 속성은 CSRF 공격 방어
// POST방식으로 값을 넘기는 곳에는 모두 <input name="_csrf" type="hidden" value="fk2031a-sd~" 같은 숨겨진 값 전송
// csrf 방어 사용시 로그아웃을 post 방식으로 해야 함
<access-denied-handler error-page="/login/accessDenied.do" />
</http>
<!-- provider -->
<authentication-manager>
<authentication-provider>
<user-service>
<user authorities="ROLE_USER" password="password" name="user" />
<user authorities="ROLE_ADMIN" password="password" name="admin"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
- access 속성
- "permitAll" : 로그인 없이 접근 가능
- "hasRole('ROLE_ADMIN')" : ADMIN 권한이 있어야 접근 가능
- "hasAnyRole('ROLE_USER, ROLE_ADMIN')" : USER나 ADMIN이면 접근
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>
<!-- 서블릿 필터로 동작을 하기 때문에 요청의 앞단에서 피요한 체크 수행 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> // 스프링시큐리티 태그 사용
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
</head>
<body>
<sec:authorize access="isAnonymous()"> //익명의 사용자 (로그인 안된 사용자)
<p><a href="<c:url value="/login/loginForm.do" />">로그인</a></p>
</sec:authorize>
<sec:authorize access="isAuthenticated()"> //로그인 된 사용자
<form:form action="${pageContext.request.contextPath }/login/logout.do" method="POST">
<input type="submit" value="로그아웃" />
</form:form>
</sec:authorize>
[<a href="<c:url value='/admin/adminHome.do' />">관리자 홈</a>]
</body>
</html>
loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<c:url value="/login" var="loginUrl" />
<form:form name="f" action="${loginUrl }" method="POST" >
<c:if test="${param.error != null }">
<p>아이디와 비밀번호가 잘못되었습니다.</p>
</c:if>
<c:if test="${param.logout != null }">
<p>로그아웃 하였습니다.</p>
</c:if>
<p>
<label for="username">아이디</label>
<input type="text" id="id" name="id" /> // name 을 기본값이 "username"이 아니라 "id" 로 변경
</p>
<p>
<label for="password">비밀번호</label>
<input type="password" id="password" name="password" />
</p>
<button type="submit" class="btn">로그인</button>
</form:form>
</body>
</html>
반응형
'프로그래밍 > JAVA' 카테고리의 다른 글
JAVA - TCP 소켓 프로그래밍 (0) | 2021.04.19 |
---|---|
30강. (JAVA) 자바 - 중첩 인터페이스 (0) | 2021.03.16 |
29강. (JAVA) 자바 - 중첩 클래스 (0) | 2020.06.30 |
28강. (JAVA) 자바 - 인터페이스(interface) (0) | 2020.06.21 |
27강. (JAVA) 자바 - 추상 클래스, 추상화 (0) | 2020.06.19 |
Comments