스프링 시큐리티 로그인 Handler Ajax #3 : Spring Framework Security Login Ajax 스프링프레임워크 #3
2014. 9. 4. 18:44 개발노트/Spring
스프링 시큐리티 로그인 Handler Ajax #3
스프링 시큐리티 연재 포스팅
2014/08/29 - [개발노트/Spring] - 스프링 시큐리티 로그인 #1 : Spring Framework Security Login 스프링프레임워크 #1
2014/09/04 - [개발노트/Spring] - 스프링 시큐리티 로그인 커스텀 #2 : Spring Framework Security Login Custom 스프링프레임워크 #2
2014/09/04 - [개발노트/Spring] - 스프링 시큐리티 로그인 Handler Ajax #3 : Spring Framework Security Login Ajax 스프링프레임워크 #3
2014/10/25 - [개발노트/Spring] - 스프링 시큐리티 커스텀 로그인 : Spring Security Custom Login UserDetailsService AuthenticationProvider #4 스프링프레임워크/Spring Framework
개발환경
Mac OS X 10.9.4
JAVA 1.6
Apache Tomcat 7.x
Spring 3.1.1
Spring Tool Suite 3.5.1
Maven 2.5.1
jQuery 1.11.1
이번에는 로그인을 ajax 방식으로 요청하고 핸들러를 이용하여 결과를 전달하는 방법을 알아보자.
다양한 예제를 위핸 ajax 방식와 submit 방식을 모두 구현하였고, 응답방식은 xml,json,html 3가지를 지원한다.
@소스 pom.xml
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!— CGLib —>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
<type>jar</type>
<scope>compile</scope>
</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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
">
<http auto-config="true" use-expressions="true" access-denied-page="/denied">
<form-login
login-page="/signin"
username-parameter="user_id"
password-parameter="password"
authentication-success-handler-ref="signinSuccessHandler"
authentication-failure-handler-ref="signinFailureHandler"
default-target-url="/mypage"
always-use-default-target="false"
/>
<logout
invalidate-session="true"
logout-success-url="/signin"
logout-url="/signout" />
</http>
<beans:bean id="signinSuccessHandler" class="com.syaku.security.SigninSuccessHandler" />
<beans:bean id="signinFailureHandler" class="com.syaku.security.SigninFailureHandler">
<beans:property name="defaultFailureUrl" value="/signin?error=true" />
</beans:bean>
<authentication-manager>
<authentication-provider>
<password-encoder ref="passwordEncoder"/>
<user-service>
<user name="guest" password="35675e68f4b5af7b995d9205ad0fc43842f16450" authorities="ROLE_USER"/>
<user name="admin" password="d033e22ae348aeb5660fc2140aec35850c4da997" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<beans:bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder" />
</beans:beans>
스프링 시큐리티 설정에서 authentication-success-handler-ref, authentication-failure-handler-ref 추가하고 아래 클래스 빈을 적용하였다.
로그인 실패될 경우 호출되는 authentication-failure-url
속성은 삭제되었다. 그래서 defaultFailureUrl 프로퍼티를 이용하여 url를 리다이렉트되게 구현하였다.
로그인을 성공하면 authentication-success-handler-ref 호출되고, 실패하면 authentication-failure-handler-ref 호출된다.
@소스 SigninSuccessHandler.java
package com.syaku.security;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
public class SigninSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(SigninSuccessHandler.class);
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
String accept = request.getHeader("accept");
if( StringUtils.indexOf(accept, "html") > -1 ) {
super.onAuthenticationSuccess(request, response, auth);
} else if( StringUtils.indexOf(accept, "xml") > -1 ) {
response.setContentType("application/xml");
response.setCharacterEncoding("utf-8");
String data = StringUtils.join(new String[] {
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<response>",
"<error>false</error>",
"<message>로그인하였습니다.</message>",
"</response>"
});
PrintWriter out = response.getWriter();
out.print(data);
out.flush();
out.close();
} else if( StringUtils.indexOf(accept, "json") > -1 ) {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
String data = StringUtils.join(new String[] {
" { \"response\" : {",
" \"error\" : false , ",
" \"message\" : \"로그인하였습니다.\" ",
"} } "
});
PrintWriter out = response.getWriter();
out.print(data);
out.flush();
out.close();
}
}
}
응답 방식을 accept 에 담아 형식을 확인한다. response.setCharacterEncoding("utf-8");
언어셋을 먼저 지정하고 PrintWriter out = response.getWriter();
선언해야 한다.
@소스 SigninFailureHandler.java
package com.syaku.security;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
public class SigninFailureHandler extends SimpleUrlAuthenticationFailureHandler {
public static String DEFAULT_TARGET_PARAMETER = "spring-security-redirect-login-failure";
private String targetUrlParameter = DEFAULT_TARGET_PARAMETER;
public String getTargetUrlParameter() {
return targetUrlParameter;
}
public void setTargetUrlParameter(String targetUrlParameter) {
this.targetUrlParameter = targetUrlParameter;
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String accept = request.getHeader("accept");
String error = "true";
String message = "로그인실패하였습니다.";
if( StringUtils.indexOf(accept, "html") > -1 ) {
String redirectUrl = request.getParameter(this.targetUrlParameter);
if (redirectUrl != null) {
super.logger.debug("Found redirect URL: " + redirectUrl);
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
} else {
super.onAuthenticationFailure(request, response, exception);
}
} else if( StringUtils.indexOf(accept, "xml") > -1 ) {
response.setContentType("application/xml");
response.setCharacterEncoding("utf-8");
String data = StringUtils.join(new String[] {
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<response>",
"<error>" , error , "</error>",
"<message>" , message , "</message>",
"</response>"
});
PrintWriter out = response.getWriter();
out.print(data);
out.flush();
out.close();
} else if( StringUtils.indexOf(accept, "json") > -1 ) {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
String data = StringUtils.join(new String[] {
" { \"response\" : {",
" \"error\" : " , error , ", ",
" \"message\" : \"", message , "\" ",
"} } "
});
PrintWriter out = response.getWriter();
out.print(data);
out.flush();
out.close();
}
}
}
마지막으로 로그인 뷰페이지를 수정한다.
@소스 signin.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Spring security</title>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
</head>
<body>
<script>
function get_msg(message) {
var move = '70px';
jQuery('#message').text(message);
jQuery('#message').animate({
top : '+=' + move
}, 'slow', function() {
jQuery('#message').delay(1000).animate({ top : '-=' + move }, 'slow');
});
}
<c:if test="${error == 'true'}">
jQuery(function() {
get_msg("로그인 실패하였습니다.");
});
</c:if>
function signin() {
$.ajax({
url : './j_spring_security_check',
data: $('form input').serialize(),
type: 'POST',
dataType : 'json',
beforeSend: function(xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
}).done(function(body) {
var message = body.response.message;
var error = body.response.error;
if (error) get_msg(message);
if (error == false) {
var url = '${referer}';
if (url == '') url = '<c:url value="/mypage" />';
location.href = url;
}
});
}
</script>
<div>
<div id="message" style="width:300px;position:absolute; top:-60px;border: 1px;border-color: #000;"></div>
</div>
<div style="margin-top:100px;">
<form id="form" action="./j_spring_security_check" method="post">
아이디 : <input type="text" id="user_id" name="user_id">
비밀번호 : <input type="password" id="password" name="password">
<button type="button" onclick="signin();">Ajax Sign in</button>
<button type="submit">Submit Sign in</button>
</form>
</div>
</body>
</html>
버튼을 2개를 만들었다. Ajax 용 버튼과 Submit 용 버튼이며, Submit 은 리다이렉트되는 방식으로 구현하였다.
'개발노트 > Spring' 카테고리의 다른 글
Spring myBATIS forEach : 스프링 프레임워크 (0) | 2014.10.02 |
---|---|
스프링 JdbcTemplate HSQLDB : Spring Framework : 스프링프레임워크 #1 (0) | 2014.09.24 |
스프링 시큐리티 로그인 커스텀 #2 : Spring Framework Security Login Custom 스프링프레임워크 #2 (2) | 2014.09.04 |
스프링 시큐리티 로그인 #1 : Spring Framework Security Login 스프링프레임워크 #1 (3) | 2014.08.29 |