깃허브:https://github.com/leejeongchan/springSecurity.git
설명하기 앞서 웹 세큐리티 설정을 모르시는 분은 아래를 타고 다시 보시기 바랍니다.
2019/05/25 - [웹/Spring] - 웹 시큐리티(Web Security)-1Day
로그인과 로그아웃 처리
우선 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">
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll"/>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
<security:form-login/>
</security:http>
<security:authentication-manager>
</security:authentication-manager>
</beans>
intercept-url을 이용해서 접근 제한을 설정합니다.
pattern 속성과 access 속성을 지정해줘야 합니다.
/sample/member URI는 ROLE_MEMBER라는 권한이 있는 사용자만 접근이 가능하다는 것을 뜻합니다.
access는 표현식과 문자열 두 방법이 있는데 만약에 문자열만 이용하고 싶으면 use expressions="false"를 이용합니다.
이렇게 설정 시 /sample/all 경로 시 아래처럼 뜨지만
만약 /sample/member를 치게되면 스프링 세큐리티 기본 설정에 의해서 로그인 화면으로 이동합니다.
신기하게도 로그인 화면을 만들지도 않았는데 말이죠
스프링 세큐리티에서는 User와 username의 의미가 아래와 같습니다.
username: 아이디와 같다.
User: 인증 정보와 권한을 가진 객체
실제 인증 처리 권한 처리는 UserDetailsService가 처리를 진행하는데 이를 등록해줍시다.
위 security-context.xml에 이어서 작성합니다.
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="member" authorities="ROLE_MEMBER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
위 설정은 저번 게시글에 그림과 비슷합니다.
member라는 정보를 추가한 후 로그인이 가능하게 하도록 한 것입니다.
그러나 위와 같은 에러가 발생하게 됩니다.
왜냐하면 PasswordEncoder가 없기 때문입니다.
만일 인코딩 없이 처리하고 싶으면 패스워드 앞에 {noop}을 작성합니다.
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
그럼 위처럼 로그인이 가능하게 됩니다.
이제 로그아웃을 처리합시다.
로그아웃은 브라우저에서 세션과 관련 정보를 삭제합니다. F12를 눌러서 Application을 보면 Cookies에 JSESSIONID로
유지하는 것을 볼 수 있습니다. 이는 톰캣 자체적으로 발생하는 쿠키 이름입니다.
로그아웃은 바로 이 JSESSIONID 쿠키를 삭제하는 겁니다.
그럼 바로 로그인 화면으로 이동하는 것을 볼 수 있습니다.
웹을 이용해 로그아웃을 하는 것은 조금 더 뒤에서 보도록 하겠습니다.
우선 sample/all과 sample/member는 처리가 됐고 남은 sample/admin이 있습니다.
이는 관리자 권한으로 member에 부여했던 것과 ROLE_ADMIN을 추가해줍니다.
<?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">
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll"/>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')"/>
<security:form-login/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN, ROLE_MEMBER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
이렇게 되면 ADMIN은 /sample/admin 과 /sample/member 모두에 접근 가능합니다.
admin으로 로그인 하면 member로 이동하는 것을 볼 수 있습니다.
이제 접근 제한 메시지를 처리합시다.
특정 사용자가 로그인 후 접근 못하도록 하는 상황이 발생할 수 있습니다.
여기선 member가 /sample/admin을 접근하지 못하도록 막습니다.
위와 같은 에러 메시지를 출력합니다.
이 접근 제한을 AccessDeniedHanlder에서 구현하거나 특정 URI를 지정합니다.
특정 URI
<security:access-denied-handler error-page="/accessError"/>
를 추가해줍니다.
/accessError를 처리하도록 CommonController를 작성합니다.
package org.zerock.controller;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
public class CommonController {
@GetMapping("/accessError")
public void accessDenied(Authentication auth,Model model) {
log.info("access Denied: "+auth);
model.addAttribute("msg","Access Denied");
}
}
Get방식으로 /accessError로 Authentication 타입 파라미터를 지정하고 Model에 에러메세지를 추가합니다.
그 다음 accessError.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 uri="http://www.springframework.org/security/tags" prefix="sec" %>
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Access Denied page</h1>
<h2><c:out value="${SPRING_SECURITY_403_EXCEPTION.getMessage()}"/></h2>
<h2><c:out value="${msg}"></c:out></h2>
</body>
</html>
만약에 admin에 member가 접근하려 한다면 아래와 같이 출력이 됩니다.
만약 다양하게 처리하고 싶다면 직접 AccessDeniedHanlder에서 구현 하도록 합니다.
예를 들어서 접근 제한 될 경우 세션, 쿠키에 특정 작업, 헤더 정보 추가 등을 말합니다.
AccessDeniedHanlder에서 구현
우선 CustomeAccessDeniedHandler 클래스를 추가합니다.
그 다음 AccessDeniedHanlder 인터페이스를 구현해줍니다.
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.log4j.Log4j;
@Log4j
public class CustomeAccessDeniedHandler implements AccessDeniedHandler{
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
// TODO Auto-generated method stub
log.error("Access Denied Handler");
log.error("Redirect.....");
response.sendRedirect("/accessError");
}
}
구현 하고 리다이렉트로 /accessError를 해줍니다. 서블릿 API를 이용하는 처리가 가능합니다.
이를 이용하기 위해 위에서와는 달리 security-context.xml에서
다음과 같이 작성을 해줍니다.( CustomeAccessDeniedHanlder를 bean으로 등록)
<bean id="customAccessDenied" class="org.zerock.security.CustomAccessDeniedHandler">
</bean>
을 <security:http> 위에 작성해주고 access-denied-hanlder에서 error-page가 아닌 ref로 바꿔줍니다.
둘중 하나를 작성합니다.
<!-- <security:access-denied-handler error-page="/accessError"/> -->
<security:access-denied-handler ref="customAccessDenied"/>
이렇게 되면 접근 제한시 리다이렉트로 동작을 하게 됩니다.
'웹 > Spring' 카테고리의 다른 글
웹 시큐리티(Web Security)-4Day[CSRF] (0) | 2019.05.28 |
---|---|
웹 시큐리티(Web Security)-3Day (0) | 2019.05.27 |
웹 시큐리티(Web Security)-1Day (0) | 2019.05.25 |
Spring 트랜잭션 설정 (0) | 2019.05.06 |
Spring 트랜잭션 & 데이터베이스 설계 (0) | 2019.05.06 |