스프링시큐티를 활용하여 ajax 로 비동기 로그인 처리
수정 소스
수정소스
- 로그인 페이지 처리
LoginController.java
loginForm.jsp
loginForm.js
- 사용자 조회
LoginService.java
LoginMapper.java
LoginMapper.xml
- 스프링시큐리티 설정
SecurityConfig.java
CustomAuthenticationSuccessHandler.java
CustomAuthenticationFailureHandler.java
LoginProvider.java
1. 로그인 페이지 처리
1) LoginController.java : 로그인 페이지 이동 컨트롤러
package com.gradle.gradletemplate.login.controller;
import com.gradle.gradletemplate.login.service.LoginService;
import com.gradle.gradletemplate.login.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
// 로그인 페이지
@RequestMapping(value = "/login/loginForm", method = {RequestMethod.GET})
public ModelAndView login() {
ModelAndView mv = new ModelAndView();
mv.setViewName("login/loginForm");
return mv;
}
}
2) loginForm.jsp : 로그인 화면
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/bootstrap/css/signin.css"/>
</head>
<div class="container">
<h2 class="form-signin-heading">Gradle Sign in</h2>
<form id="frm_login" method="post">
<label for="userId" class="sr-only">Email address</label>
<input type="email" id="userId" name="userId" class="form-control" placeholder="Email address">
<label for="userPw" class="sr-only">Password</label>
<input type="password" id="userPw" name="userPw" class="form-control" placeholder="Password">
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> ID 저장
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="button" id="btn_signin">Sign in</button>
</form>
</div>
</html>
3) loginForm.js : 로그인 화면 스크립트
var loginForm = {
init: function() {
loginForm.bind();
},
bind: function() {
$("#btn_signin").on('click', function(){
loginForm.signin();
});
},
signin: function() {
$.ajax({
url: '/login',
type: 'POST',
dataType: 'json',
data: {
userId: $("#userId").val(),
userPw: $("#userPw").val()
},
success: function(res){
if(res.code=='200'){
alert("로그인 되었습니다.");
common.goPage("/board/boardList");
} else {
alert(res.message);
}
console.log(res);
}
});
}
}
$(function(){
loginForm.init();
});
2. 사용자 조회
1) LoginService.java : 사용자 조회 매퍼 호출
package com.gradle.gradletemplate.login.service;
import com.gradle.gradletemplate.login.mapper.LoginMapper;
import com.gradle.gradletemplate.login.vo.UserVO;
import com.gradle.gradletemplate.util.CryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class LoginService {
@Autowired
private LoginMapper loginMapper;
// 사용자 조회
public UserVO selectUser(UserVO userVO) {
return loginMapper.selectUser(userVO);
}
}
2) LoginMapper.java : 사용자 조회 쿼리 호출
package com.gradle.gradletemplate.login.mapper;
import com.gradle.gradletemplate.login.vo.UserVO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LoginMapper {
// 사용자 조회
UserVO selectUser(UserVO userVO);
}
3) LoginMapper.xml : 사용자 조회 쿼리
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gradle.gradletemplate.login.mapper.LoginMapper">
<select id="selectUser" parameterType="com.gradle.gradletemplate.login.vo.UserVO" resultType="com.gradle.gradletemplate.login.vo.UserVO">
select USER_ID
, USER_PW
, USER_NAME
, PHONE
, EMAIL
, ROLE
, CREATED_TIME
, UPDATE_TIME
from user
where USER_ID = #{userId}
</select>
</mapper>
3. 스프링 시큐리티 설정
1) SecurityConfig.java : 로인과 관련된 세션정보 체크, 로그인페이지, 로그인 처리 프로세스 및 핸들러 등에 대한 설정을 한다.
package com.gradle.gradletemplate.config;
import com.gradle.gradletemplate.config.security.CustomAuthenticationFailureHandler;
import com.gradle.gradletemplate.config.security.CustomAuthenticationSuccessHandler;
import com.gradle.gradletemplate.config.security.CustomUserDetailsService;
import com.gradle.gradletemplate.config.security.LoginProvider;
import lombok.RequiredArgsConstructor;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@RequiredArgsConstructor
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
private LoginProvider loginProvider;
// 인증 예외처리
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/bootstrap/**", "/common/**", "/jquery/**", "/js/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/notice/**").authenticated() // 해당 URL 패턴에 대해 로그인 했을 경우에만 접근 허용
.antMatchers("/board/**").hasAuthority("MEMBER") // 해당 URL 패턴에 대해 MEMBER 권한이 있을 경우에만 접근 허용
.anyRequest().permitAll() // 위에 설정된 URL 패턴을 제외한 모든 페이지 접근 허용
.and()
.formLogin()
.loginPage("/login/loginForm") // 접근 허용이 되지 않은 페이지에 접근 했을 경우 해당 URL 로 이동
.loginProcessingUrl("/login") // 해당 URL 로 접근 시 로그인 프로세스 실행
.usernameParameter("userId") // 사용자아이디 파라미터 name을 정의
.passwordParameter("userPw") // 비밀번호 파라미터 name을 정의
.successHandler(customAuthenticationSuccessHandler) // 로그인 성공시 해당 핸들러 실행
.failureHandler(customAuthenticationFailureHandler) // 로그인 실패시 해당 핸들러 실행
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true).deleteCookies("JSESSIONID")
// ajax 통신 가능하도록
.and()
.csrf()
.disable()
.authenticationProvider(loginProvider)
;
}
}
2) LoginProvider.java : 로인 처리 프로세스
package com.gradle.gradletemplate.config.security;
import com.gradle.gradletemplate.login.service.LoginService;
import com.gradle.gradletemplate.login.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
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.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
public class LoginProvider implements AuthenticationProvider {
@Autowired
private LoginService loginService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Object details = authentication.getDetails();
String userId = authentication.getName();
String userPw = (String) authentication.getCredentials();
String resultUserPw = "";
Object resultObj = null;
UserVO param = new UserVO();
param.setUserId(userId);
param.setUserPw(userPw);
UserVO userInfo = loginService.selectUser(param);
// 사용자 존재여부
if(userInfo==null) {
throw new BadCredentialsException("아이디가 존재하지 않습니다.");
} else {
resultUserPw = userInfo.getUserPw();
userInfo.setUserPw(null);
resultObj = userInfo;
}
// 비밀번호 체크
if(!userPw.equals(resultUserPw)){
throw new BadCredentialsException("비밀번호가 일치하지 않습니다.");
}
// 권한 리스트
List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
roles.add(new SimpleGrantedAuthority("MEMBER")); // 별도 권한 관리는 만들지 않아 임의로 입력
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userId, userPw, roles);
authToken.setDetails(resultObj);
return authToken;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
3) CustomAuthenticationSuccessHandler.java : 로그인 성공시 처리 로직
package com.gradle.gradletemplate.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gradle.gradletemplate.common.constant.ResponseDataCode;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(authentication.getName());
System.out.println(authentication.getCredentials());
ResponseDataDTO responseDataDTO = new ResponseDataDTO();
responseDataDTO.setCode(ResponseDataCode.SUCCESS);
responseDataDTO.setStatus(ResponseDataCode.SUCCESS);
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(mapper.writeValueAsString(responseDataDTO));
response.getWriter().flush();
}
}
4) CustomAuthenticationFailureHandler.java : 로그인 실패시 처리 로직
package com.gradle.gradletemplate.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gradle.gradletemplate.common.constant.ResponseDataCode;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
ObjectMapper mapper = new ObjectMapper();
ResponseDataDTO responseDataDTO = new ResponseDataDTO();
responseDataDTO.setCode(ResponseDataCode.ERROR);
responseDataDTO.setStatus(ResponseDataCode.ERROR);
responseDataDTO.setMessage(exception.getMessage());
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println(mapper.writeValueAsString(responseDataDTO));
response.getWriter().flush();
}
}
'스프링부트+gradle+JSP+STS(Eclipse)' 카테고리의 다른 글
스프링부트 ajax JSON 통신 (0) | 2022.05.23 |
---|---|
스프링부트 부트스트랩(bootstrap) 적용하기 (0) | 2022.05.20 |
스프링부트 인터셉터(Interceptor) 설정 (0) | 2022.05.09 |
스프링부트 tiles(타일즈) 설정 (2) | 2022.05.09 |
Mysql 사용자 계정 생성 (0) | 2022.05.06 |
댓글