본문 바로가기

학원/복기

[Spring Security] rememberme 예제

login_page.jsp

<input type="checkbox" name="remember-me">자동 로그인

 

security-context.xml

<remember-me token-validity-seconds="604800"/>

 

remember-me : 자동 로그인 기능을 제공하기 위한 엘리먼트 

  • 사용자 인증 처리를 요청하기 전에 [remember-me] 이름의 쿠키를 검색하여 로그인 처리함
  • [remember-me] 이름의 쿠키에는 자동 로그인 관련 토큰이 자동으로 생성되어 저장됨

token-validity-seconds 속성 : 자동 로그인 기능을 유지하기 위한 시간(초)을 속성값으로 설정 

 

 

 

브라우저를 닫았다 열어도 로그인 상태가 유지된다.

 

하지만 쿠키에 자동 로그인 관련 토큰을 저장하는 것은 보안상 위험하므로 DB에 자동 로그인 관련 토큰을 저장하여 사용하는 것을 권장한다.

 

 

persistent_logins 테이블을 생성하여 자동 로그인 관련 정보를 저장해준다.

 

테이블 생성

CREATE TABLE persistent_logins(series VARCHAR2(100) primary key, username VARCHAR2(100)
    , token VARCHAR2(100), last_used TIMESTAMP);

 

security-context.xml

<!-- data-source-ref : persistent_logins 테이블이 저장된 DB 서버의 DataSource 객체의 Spring BeanName을 속성값으로... -->
<remember-me data-source-ref="dataSoruce" token-validity-seconds="604800"/>

 

 

로그아웃할 때 remember-me 삭제되도록 설정

<logout logout-url="/logout" logout-success-url="/" invalidate-session="true" delete-cookies="JSESSIONID"/>

 

 

logout : 로그아웃 처리 기능을 제공하는 엘리먼트 

  • logout-url 속성 : 로그아웃 처리를 위해 요청하기 위한 URL 주소를 속성값으로 설정
  • logout-success-url 속성 : 로그아웃 처리후 요청할 페이지의 URL 주소를 속성값으로 설정
  • invalidate-session 속성 : 세션을 무효화 처리하기 위한 논리값(false 또는 true)을 속성값으로 설정
  • delete-cookies 속성 : 삭제할 쿠키에 대한 이름을 속성값으로 설정

 

 

<session-management>
	<concurrency-control max-sessions="1" expired-url="/sessionError"/>
</session-management>

 

session-management : 로그인 정보가 저장된 세션을 관리하기 위한 엘리먼트

concurrency-control : 세션의 허용 갯수를 설정하는 엘리먼트

-> 다중 로그인을 방지하기 위해 사용한다. (동시 접속 차단)

  • max-sessions 속성 : 세션의 최대 허용 갯수를 속성값으로 설정
  • -> 세션의 최대 허용 갯수를 초과할 경우 기존 세션을 무효화 처리하고 새로운 세션에 로그인 정보를 저장하여 사용한다.
  • expired-url 속성 :  세션의 최대 허용 갯수를 초과할 경우 이동될 페이지의 URL 주소를 속성값으로 설정한다.
  • error-if-maximum-exceeded 속성 : false 또는 true 중 하나를 속성값으로 설정한다.
    • -> 속성값을 true 로 설정한 경우 기존 세션을 유지하고 새로운 세션을 무효화 처리한다.

 

 

 

LoginController

	@RequestMapping(value = "/sessionError", method = RequestMethod.GET)
	public String sessionError() {
		return "session_error";
	}

 

session_error.jsp

<h1>에러페이지</h1>
<hr>
<h3 style="color: red;">다른 컴퓨터에서 접속 하였습니다. 확인해 보세요.</h3>
<hr>
<h3><a href="<c:url value="/"/>">메인으로</a></h3>

 

home.jsp

	<%-- 로그인 사용자 정보 저장 --%>
	<sec:authentication property="principal" var="loginUser"/>
	
	<%-- 인증된 사용자인 경우 태그가 포함되도록 설정 --%>
	<sec:authorize access="isAuthenticated()">
		<%-- <h3><sec:authentication property="principal.username"/>님, 환영합니다.</h3>--%>
		<%-- <h3><sec:authentication property="principal.name"/>님, 환영합니다.</h3>--%>
		<h3>${loginUser.name }님, 환영합니다.</h3>
	
		<%-- 로그아웃 처리 기능을 제공하는 페이지는 반드시 form 태그를 사용하여 요청 --%>
		<%-- => CSRF 토큰을 전달하여 처리되도록 설정 --%>
		<form action="<c:url value="/logout"/>" method="post">
			<sec:csrfInput/>
			<button type="submit">로그아웃</button>
		</form>
	</sec:authorize>

 


HomeController

 

@Slf4j
@Controller
public class HomeController {
	
	//Principal 객체 : 로그인된 사용자의 정보와 권한 정보가 저장된 객체
    	// => Principal.getName() 메소드로 아이디만 제공받아 사용 가능
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Principal principal) {
		if(principal != null) {
			log.warn("아이디 = "+principal.getName());
		}
			
		return "home";
	}
    ...
    ...
}

다른 방법

 

HomeControlelr

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Authentication authentication) {
		if(authentication != null) {
			CustomUserDetails users=(CustomUserDetails)authentication.getPrincipal();
			log.warn("아이디 = "+users.getUserid());
			log.warn("이름 = "+users.getName());
			log.warn("이메일 = "+users.getEmail());
		}
			
		return "home";
	}

 

 

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Principal principal) {
		if(principal != null) {
			log.warn("아이디 = "+principal.getName());
			
			SecurityUsers users=securityUsersService.getSecurityUsers(principal.getName());
			
			log.warn("아이디 = "+users.getUserid());
			log.warn("이름 = "+users.getName());
			log.warn("이메일 = "+users.getEmail());
		}
			
		return "home";
	}

 

두 방법 중 하면 됨