authenticate메서드에서 pw확인 로직을 안넣었더니, 비밀번호 뭘넣든 그냥 승인됨..ㅜ matches함수로 검증로직추가함, 로그인 성공 실패시 적용될 handler클래스와 config설정도 추가해주었음..
This commit is contained in:
@@ -8,6 +8,7 @@ import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -19,6 +20,9 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@@ -28,8 +32,15 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
log.info("### authenticate ### ");
|
||||
|
||||
String username = (String) authentication.getPrincipal();
|
||||
String password = (String) authentication.getCredentials();
|
||||
String passwordEnc = passwordEncoder.encode(password);
|
||||
|
||||
Account account = (Account) accountService.loadUserByUsername(username);
|
||||
|
||||
// pw같은지 검증.
|
||||
if ( !passwordEncoder.matches(password,account.getPassword())) {
|
||||
throw new BadCredentialsException(username);
|
||||
}
|
||||
|
||||
return new UsernamePasswordAuthenticationToken(account, account, account.getAuthorities());
|
||||
}
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
package com.boot.test1.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
|
||||
import com.boot.test1.handler.CustomAuthenticationFailureHandler;
|
||||
import com.boot.test1.handler.CustomAuthenticationSuccessHandler;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter{
|
||||
|
||||
@Autowired
|
||||
private AuthenticationSuccessHandler successHandler;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationFailureHandler failureHandler;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception{
|
||||
http
|
||||
@@ -24,7 +36,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter{
|
||||
.loginPage("/login") // 로그인이 수행될 경로.
|
||||
.loginProcessingUrl("/loginProcess")// 로그인form의 action과 일치시켜주어야 함.
|
||||
.defaultSuccessUrl("/loginSuccess") // 로그인 성공 시 이동할 경로.
|
||||
.failureUrl("/login?error=true") // 인증에 실패했을 때 보여주는 화면 url, 로그인 form으로 파라미터값 error=true로 보낸
|
||||
//.failureUrl("/login?error=true") // 인증에 실패했을 때 보여주는 화면 url, 로그인 form으로 파라미터값 error=true로 보낸다.
|
||||
.successHandler(successHandler)
|
||||
.failureHandler(failureHandler)
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
@@ -47,6 +61,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter{
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
|
||||
// 로그인 성공 처리를 위한 Handler
|
||||
@Bean
|
||||
public AuthenticationSuccessHandler successHandler() {
|
||||
return new CustomAuthenticationSuccessHandler("loginRedirect", "/login", false);
|
||||
}
|
||||
|
||||
// 실패 처리를 위한 Handler
|
||||
@Bean
|
||||
public AuthenticationFailureHandler failureHandler() {
|
||||
return new CustomAuthenticationFailureHandler("username", "password" , "loginRedirect" , "securityExceptionMsg" , "/login?fail=true");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.boot.test1.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
|
||||
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
private String loginIdName ;
|
||||
private String loginPasswordName ;
|
||||
private String loginRedirectName ;
|
||||
private String exceptionMsgName ;
|
||||
private String defaultFailureUrl ;
|
||||
|
||||
public CustomAuthenticationFailureHandler(String loginIdName, String loginPasswordName, String loginRedirectName,
|
||||
String exceptionMsgName, String defaultFailureUrl) {
|
||||
this.loginIdName = loginIdName;
|
||||
this.loginPasswordName = loginPasswordName;
|
||||
this.loginRedirectName = loginRedirectName;
|
||||
this.exceptionMsgName = exceptionMsgName;
|
||||
this.defaultFailureUrl = defaultFailureUrl;
|
||||
}
|
||||
|
||||
public String getLoginIdName() {
|
||||
return loginIdName;
|
||||
}
|
||||
public void setLoginIdName(String loginIdName) {
|
||||
this.loginIdName = loginIdName;
|
||||
}
|
||||
public String getLoginPasswordName() {
|
||||
return loginPasswordName;
|
||||
}
|
||||
public void setLoginPasswordName(String loginPasswordName) {
|
||||
this.loginPasswordName = loginPasswordName;
|
||||
}
|
||||
public String getLoginRedirectName() {
|
||||
return loginRedirectName;
|
||||
}
|
||||
public void setLoginRedirectName(String loginRedirectName) {
|
||||
this.loginRedirectName = loginRedirectName;
|
||||
}
|
||||
public String getExceptionMsgName() {
|
||||
return exceptionMsgName;
|
||||
}
|
||||
public void setExceptionMsgName(String exceptionMsgName) {
|
||||
this.exceptionMsgName = exceptionMsgName;
|
||||
}
|
||||
public String getDefaultFailureUrl() {
|
||||
return defaultFailureUrl;
|
||||
}
|
||||
public void setDefaultFailureUrl(String defaultFailureUrl) {
|
||||
this.defaultFailureUrl = defaultFailureUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
|
||||
String loginId = request.getParameter(loginIdName);
|
||||
String loginPw = request.getParameter(loginPasswordName);
|
||||
String loginRedirect = request.getParameter(loginRedirectName);
|
||||
|
||||
request.setAttribute(loginIdName, loginId);
|
||||
request.setAttribute(loginPasswordName, loginPw);
|
||||
request.setAttribute(loginRedirectName, loginRedirect);
|
||||
|
||||
request.setAttribute(exceptionMsgName, exception.getMessage());
|
||||
|
||||
request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.boot.test1.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.WebAttributes;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
// RedirectStrategy은 화면을 이동하기위한 인터페이스이다.
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
|
||||
private String targetUrlParameter ;
|
||||
private String defaultUrl ;
|
||||
private boolean useReferer ;
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
// constructor
|
||||
public CustomAuthenticationSuccessHandler(String targetUrlParameter, String defaultUrl ,boolean useReferer) {
|
||||
this.targetUrlParameter=targetUrlParameter;
|
||||
this.defaultUrl=defaultUrl;
|
||||
this.useReferer = useReferer;
|
||||
log.info(" targetUrlParameter : " , targetUrlParameter + ", defaultUrl : " + defaultUrl +", useReferer : " + useReferer );
|
||||
}
|
||||
|
||||
// getter, settger
|
||||
public String getTargetUrlParameter() {
|
||||
return targetUrlParameter;
|
||||
}
|
||||
|
||||
|
||||
public void setTargetUrlParameter(String targetUrlParameter) {
|
||||
this.targetUrlParameter = targetUrlParameter;
|
||||
}
|
||||
|
||||
|
||||
public String getDefaultUrl() {
|
||||
return defaultUrl;
|
||||
}
|
||||
|
||||
|
||||
public void setDefaultUrl(String defaultUrl) {
|
||||
this.defaultUrl = defaultUrl;
|
||||
}
|
||||
|
||||
|
||||
public boolean isUseReferer() {
|
||||
return useReferer;
|
||||
}
|
||||
|
||||
|
||||
public void setUseReferer(boolean useReferer) {
|
||||
this.useReferer = useReferer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException, ServletException {
|
||||
|
||||
clearAuthenticationAttributes(request);
|
||||
|
||||
int intRedirectStrategy = decideRedirectStrategy(request,response);
|
||||
|
||||
switch(intRedirectStrategy) {
|
||||
|
||||
case 1:
|
||||
useTargetUrl(request, response);
|
||||
break;
|
||||
case 2:
|
||||
useSessionUrl(request, response);
|
||||
break;
|
||||
case 3:
|
||||
useRefererUrl(request, response);
|
||||
break;
|
||||
default:
|
||||
useDefaultUrl(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 인증 성공 후 어떤 URL로 redirect 할지를 결정한다.
|
||||
*
|
||||
* 판단 기준은 targetUrlParameter 값을 읽은 URL이 존재할 경우 그것을 1순위
|
||||
*
|
||||
* 1순위 URL이 없을 경우 Spring Security가 세션에 저장한 URL을 2순위
|
||||
* 2순위 URL이 없을 경우 Request의 REFERER를 사용하고 그 REFERER URL이 존재할 경우 그 URL을 3순위
|
||||
* 3순위 URL이 없을 경우 Default URL을 4순위로 한다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return 1 : targetUrlParameter 값을 읽은 URL
|
||||
* 2 : Session에 저장되어 있는 URL
|
||||
* 3 : referer 헤더에 있는 URL
|
||||
* 0 : default URL
|
||||
*/
|
||||
|
||||
private int decideRedirectStrategy(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
int result = 0 ;
|
||||
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
|
||||
if ( !"".equals(targetUrlParameter) ) {
|
||||
|
||||
String targetUrl = request.getParameter(targetUrlParameter);
|
||||
|
||||
if(StringUtils.hasText(targetUrl)) {
|
||||
result = 1;
|
||||
}else {
|
||||
if (savedRequest != null ) result=2;
|
||||
else {
|
||||
String refererUrl = request.getHeader("REFERER");
|
||||
if ( useReferer && StringUtils.hasText(refererUrl)) result = 3;
|
||||
else result = 0 ;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if( savedRequest != null ) {
|
||||
result = 2 ;
|
||||
return result ;
|
||||
}
|
||||
|
||||
String refererUrl = request.getHeader("REFERER");
|
||||
if(useReferer && StringUtils.hasText(refererUrl)) result =3;
|
||||
else result = 0 ;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* 기본적으로 SpringSecurity는 로그인 실패하면 에러세션을 저장한다.
|
||||
* 그러나, 예를들어 로그인을 5번시도하고 성공했다고해도 그 에러세션이 저장되어 있을것이다.
|
||||
* 이 남아있는 에러세션을 주기위한 메서드이다.
|
||||
*/
|
||||
private void clearAuthenticationAttributes(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
if ( session == null ) return;
|
||||
|
||||
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); // SpringSecurity는 에러발생시 해당 key값을 사용한다.
|
||||
}
|
||||
|
||||
private void useTargetUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
|
||||
if(savedRequest != null ) {
|
||||
requestCache.removeRequest(request, response);
|
||||
}
|
||||
|
||||
String targetUrl = request.getParameter(targetUrlParameter);
|
||||
redirectStrategy.sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
private void useSessionUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
String targetUrl = savedRequest.getRedirectUrl();
|
||||
redirectStrategy.sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
private void useRefererUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String targetUrl = request.getHeader("REFERER");
|
||||
redirectStrategy.sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
private void useDefaultUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
redirectStrategy.sendRedirect(request, response, defaultUrl);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -57,15 +57,15 @@
|
||||
</div>
|
||||
<button name="submit" type="submit" class="btn btn-block btn-primary text-light">로그인</button>
|
||||
|
||||
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
|
||||
<c:if test="${not empty securityExceptionMsg}">
|
||||
<%--<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}"> --%>
|
||||
<font color="red">
|
||||
<p>
|
||||
Your login attempt was not successful due to <br />
|
||||
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
|
||||
</p>
|
||||
<c:remove var="SPRING_SECURITY_LAST_EXCEPTION" scope="session" />
|
||||
<p>Your login attempt was not successful, try again</p>
|
||||
<p>${securityExceptionMsg}</p>
|
||||
<%--<c:remove var="SPRING_SECURITY_LAST_EXCEPTION" scope="session" /> --%>
|
||||
</font>
|
||||
</c:if>
|
||||
<input type="hidden" name="loginRedirect" value="${loginRedirect}" />
|
||||
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <br>
|
||||
|
||||
<sec:authorize access="isAuthenticated()">
|
||||
|
||||
Reference in New Issue
Block a user