[Spring ] 회원관리_인증처리_ 22.08.03 [15일차]
1. 회원가입
* 입력값 검증 [아이디 이메일 중복여부]
2. 로그인 / 자동로그인
* 로그인을 유지하기 위한 수단 = 세션
3. 인증처리 / 인가처리
ex) 코스트코 회원권을 들고 있다 = 인증
ex) VIP구역에 들어갈수 있는지 여부 = 인가
=== 실무에서 spring security 를 사용하지만 강의 시간에는 최대한 security를 쓰지 않고 만들어 보도록 한다.
※ 회원 수정/탈퇴는 각자 알아서[강의에서는 다루지 않는다.]
== 패스워드 암호화 빌드설정
=BCryptPasswordEncoder();
== 중복체크 기능 마이바티스 xml
== 중복확인 중간처리 service 메서드
== 회원관리 MemberController
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<%@ include file="../include/static-head.jsp" %>
</head>
<body>
<%@ include file="../include/header.jsp" %>
<div class="container">
<div class="row">
<div class="offset-md-2 col-md-4">
<div class="card" style="width:200%;">
<div class="card-header text-white" style="background: #343A40;">
<h2><span style="color: gray;">MVC</span> 회원 가입</h2>
</div>
<div class="card-body">
<form action="/member/sign-up" name="signup" id="signUpForm" method="post" style="margin-bottom: 0;">
<table style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
<tr>
<td style="text-align: left">
<p><strong>아이디를 입력해주세요.</strong>
<span id="idChk"></span></p>
</td>
</tr>
<tr>
<td><input type="text" name="account" id="user_id" class="form-control tooltipstered"
maxlength="14" required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="숫자와 영어로 4-14자">
</td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>비밀번호를 입력해주세요.</strong> <span id="pwChk"></span></p>
</td>
</tr>
<tr>
<td><input type="password" size="17" maxlength="20" id="password" name="password"
class="form-control tooltipstered" maxlength="20" required="required"
aria-required="true"
style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
placeholder="영문과 특수문자를 포함한 최소 8자"></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>비밀번호를 재확인해주세요.</strong> <span id="pwChk2"></span></p>
</td>
</tr>
<tr>
<td><input type="password" size="17" maxlength="20" id="password_check" name="pw_check"
class="form-control tooltipstered" maxlength="20" required="required"
aria-required="true"
style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
placeholder="비밀번호가 일치해야합니다."></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>이름을 입력해주세요.</strong> <span id="nameChk"></span></p>
</td>
</tr>
<tr>
<td><input type="text" name="name" id="user_name" class="form-control tooltipstered"
maxlength="6" required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="한글로 최대 6자"></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>이메일을 입력해주세요.</strong> <span id="emailChk"></span></p>
</td>
</tr>
<tr>
<td><input type="email" name="email" id="user_email" class="form-control tooltipstered"
required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="ex) abc@mvc.com"></td>
</tr>
<tr>
<td style="padding-top: 10px; text-align: center">
<p><strong>회원가입하셔서 더 많은 서비스를 사용하세요~~!</strong></p>
</td>
</tr>
<tr>
<td style="width: 100%; text-align: center; colspan: 2;">
<input type="button" value="회원가입" class="btn form-control tooltipstered"
id="signup-btn"
style="background: gray; margin-top: 0; height: 40px; color: white; border: 0px solid #388E3C; opacity: 0.8">
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
</div>
</div>
<%@ include file="../include/footer.jsp" %>
</body>
</html>
spring security 기본 로그인 폼
== void처리 => 메서드의 요청 url과 리턴 url이 같을 경우
== spring security 기본 설정 끄기
== jQuery 아이디, 이름, 패스워드, 이름 검증식
// 검증 스크립트 포함 jsp 풀버전
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<%@ include file="../include/static-head.jsp" %>
<style>
.container {
margin: 200px auto 200px;
}
.c-red {
color: red;
}
.c-blue {
color: blue;
}
</style>
</head>
<body>
<%@ include file="../include/header.jsp" %>
<div class="container">
<div class="row">
<div class="offset-md-2 col-md-4">
<div class="card" style="width:200%;">
<div class="card-header text-white" style="background: #343A40;">
<h2><span style="color: gray;">MVC</span> 회원 가입</h2>
</div>
<div class="card-body">
<form action="/member/sign-up" name="signup" id="signUpForm" method="post"
style="margin-bottom: 0;">
<table style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
<tr>
<td style="text-align: left">
<p><strong>아이디를 입력해주세요.</strong>
<span id="idChk"></span>
</p>
</td>
</tr>
<tr>
<td><input type="text" name="account" id="user_id"
class="form-control tooltipstered" maxlength="14"
required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="숫자와 영어로 4-14자">
</td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>비밀번호를 입력해주세요.</strong> <span
id="pwChk"></span></p>
</td>
</tr>
<tr>
<td><input type="password" size="17" maxlength="20" id="password"
name="password" class="form-control tooltipstered"
maxlength="20" required="required" aria-required="true"
style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
placeholder="영문과 특수문자를 포함한 최소 8자"></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>비밀번호를 재확인해주세요.</strong> <span
id="pwChk2"></span></p>
</td>
</tr>
<tr>
<td><input type="password" size="17" maxlength="20" id="password_check"
name="pw_check" class="form-control tooltipstered"
maxlength="20" required="required" aria-required="true"
style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
placeholder="비밀번호가 일치해야합니다."></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>이름을 입력해주세요.</strong> <span
id="nameChk"></span></p>
</td>
</tr>
<tr>
<td><input type="text" name="name" id="user_name"
class="form-control tooltipstered" maxlength="6"
required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="한글로 최대 6자"></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>이메일을 입력해주세요.</strong> <span
id="emailChk"></span></p>
</td>
</tr>
<tr>
<td><input type="email" name="email" id="user_email"
class="form-control tooltipstered" required="required"
aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="ex) abc@mvc.com"></td>
</tr>
<tr>
<td style="padding-top: 10px; text-align: center">
<p><strong>회원가입하셔서 더 많은 서비스를 사용하세요~~!</strong></p>
</td>
</tr>
<tr>
<td style="width: 100%; text-align: center; colspan: 2;">
<input type="button" value="회원가입"
class="btn form-control tooltipstered" id="signup-btn"
style="background: gray; margin-top: 0; height: 40px; color: white; border: 0px solid #388E3C; opacity: 0.8">
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
//회원가입 폼 검증 - jquery
$(document).ready(function () {
//입력값 검증 정규표현식
const getIdCheck = RegExp(/^[a-zA-Z0-9]{4,14}$/); // ^ : ~로 시작하는 $ : 끝나는 {4~14} : 최소~최대
const getPwCheck = RegExp(
// 영문 숫자과 들어가야하고 특수기호를 하나라도 포함해야 하고 또는 시작을 특수문자로 해도 되고
// 영문과 숫자가 들어가야한다.
/([a-zA-Z0-9].*[!,@,#,$,%,^,&,*,?,_,~])|([!,@,#,$,%,^,&,*,?,_,~].*[a-zA-Z0-9])/);
const getName = RegExp(/^[가-힣]+$/); // 한글로 써야 한다. 유니코드 시작과 끝 가 - 힣
const getMail = RegExp(/^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+/);
// 영어로 시작하고 + 골뱅이 + 영문 + . + 영문
// 입력값 검증 배열
//1.아이디, 2.비번, 3.비번확인, 4.이름 , 5.이메일
const checkArr = [false, false, false, false, false];
//1. 아이디 검증
const $idInput = $('#user_id');
$idInput.on('keyup', e => {
// 아이디를 입력하지 않은 경우
if ($idInput.val().trim() === '') {
$idInput.css('border-color', 'red');
$('#idChk').html('<b class = "c-red">[아이디는 필수 정보 입니다.]</b>')
checkArr[0] = false;
}
// 아이디를 패턴에 맞지 않게 입력 하였을 경우
// test() 메서드는 정규표현식을 검증하여 입력값이 표현식과
// 일치하면 true, 일치하지 않으면 false를 리턴
else if (!getIdCheck.test($idInput.val())) {
$idInput.css('border-color', 'red');
$('#idChk').html('<b class = "c-red">[영문,숫자로 4~14자 사이로 작성하세요!]</b>')
checkArr[0] = false;
}
// 아이디 중복 확인 검증
else {
fetch('/member/check?type=account&value=' + $idInput.val())
.then(res => res.text())
.then(flag => {
console.log('flag:', flag);
if (flag === 'true') {
$idInput.css('border-color', 'red');
$('#idChk').html('<b class = "c-red">[중복된 아이디 입니다.]</b>')
checkArr[0] = false;
} // 정상적으로 입력한 경우
else {
$idInput.css('border-color', 'skyblue');
$('#idChk').html('<b class = "c-blue">[허용 가능한 아이디 입니다.]</b>')
checkArr[0] = true;
}
});
}
}); //end id check event
//패스워드 입력값 검증.
$('#password').on('keyup', function () {
//비밀번호 공백 확인
if ($("#password").val() === "") {
$('#password').css('border-color', 'red');
$('#pwChk').html('<b class="c-red">[패스워드는 필수정보!]</b>');
checkArr[1] = false;
}
//비밀번호 유효성검사
else if (!getPwCheck.test($("#password").val()) || $("#password").val().length < 8) {
$('#password').css('border-color', 'red');
$('#pwChk').html('<b class="c-red">[특수문자 포함 8자이상]</b>');
checkArr[1] = false;
} else {
$('#password').css('border-color', 'skyblue');
$('#pwChk').html('<b class="c-blue">[참 잘했어요]</b>');
checkArr[1] = true;
}
});
//패스워드 확인란 입력값 검증.
$('#password_check').on('keyup', function () {
//비밀번호 확인란 공백 확인
if ($("#password_check").val() === "") {
$('#password_check').css('border-color', 'red');
$('#pwChk2').html('<b class="c-red">[패스워드확인은 필수정보!]</b>');
checkArr[2] = false;
}
//비밀번호 확인란 유효성검사
else if ($("#password").val() !== $("#password_check").val()) {
$('#password_check').css('border-color', 'red');
$('#pwChk2').html('<b class="c-red">[위에랑 똑같이!!]</b>');
checkArr[2] = false;
} else {
$('#password_check').css('border-color', 'skyblue');
$('#pwChk2').html('<b class="c-blue">[참 잘했어요]</b>');
checkArr[2] = true;
}
});
//이름 입력값 검증.
$('#user_name').on('keyup', function () {
//이름값 공백 확인
if ($("#user_name").val() === "") {
$('#user_name').css('border-color', 'red');
$('#nameChk').html('<b class="c-red">[이름은 필수정보!]</b>');
checkArr[3] = false;
}
//이름값 유효성검사
else if (!getName.test($("#user_name").val())) {
$('#user_name').css('border-color', 'red');
$('#nameChk').html('<b class="c-red">[이름은 한글로 ~]</b>');
checkArr[3] = false;
} else {
$('#user_name').css('border-color', 'skyblue');
$('#nameChk').html('<b class="c-blue">[참 잘했어요]</b>');
checkArr[3] = true;
}
});
//이메일 입력값 검증.
const $emailInput = $('#user_email');
$emailInput.on('keyup', function () {
//이메일값 공백 확인
if ($emailInput.val() == "") {
$emailInput.css('border-color', 'red');
$('#emailChk').html('<b class="c-red">[이메일은 필수정보에요!]</b>');
checkArr[4] = false;
}
//이메일값 유효성검사
else if (!getMail.test($emailInput.val())) {
$emailInput.css('border-color', 'red');
$('#emailChk').html('<b class="c-red">[이메일 형식 몰라?]</b>');
checkArr[4] = false;
} else {
//이메일 중복확인 비동기 통신
fetch('/member/check?type=email&value=' + $emailInput.val())
.then(res => res.text())
.then(flag => {
//console.log(flag);
if (flag === 'true') {
$emailInput.css('border-color', 'red');
$('#emailChk').html(
'<b class="c-red">[이메일이 중복되었습니다!]</b>');
checkArr[4] = false;
} else {
$emailInput.css('border-color', 'skyblue');
$('#emailChk').html(
'<b class="c-blue">[사용가능한 이메일입니다.]</b>'
);
checkArr[4] = true;
}
});
}
});
});
</script>
<%@ include file="../include/footer.jsp" %>
</body>
</html>
== 로그인 페이지 만들기
sign-in.jsp
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<%@ include file="../include/static-head.jsp" %>
<style>
.wrap {
margin: 200px auto;
}
</style>
</head>
<body>
<%@ include file="../include/header.jsp" %>
<div class="container wrap">
<div class="row">
<div class="offset-md-2 col-md-4">
<div class="card" style="width:200%;">
<div class="card-header text-white" style="background: #343A40;">
<h2><span style="color: gray;">MVC</span> 로그인</h2>
</div>
<div class="card-body">
<form action="/member/sign-in" name="sign-in" method="post" id="signInForm"
style="margin-bottom: 0;">
<table style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
<tr>
<td style="text-align: left">
<p><strong>아이디를 입력해주세요.</strong> <span id="idCheck"></span></p>
</td>
</tr>
<tr>
<td><input type="text" name="account" id="signInId"
class="form-control tooltipstered" maxlength="10"
required="required" aria-required="true"
style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
placeholder="최대 10자"></td>
</tr>
<tr>
<td style="text-align: left">
<p><strong>비밀번호를 입력해주세요.</strong> <span id="pwCheck"></span></p>
</td>
</tr>
<tr>
<td><input type="password" size="17" maxlength="20" id="signInPw"
name="password" class="form-control tooltipstered"
maxlength="20" required="required" aria-required="true"
style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
placeholder="최소 8자"></td>
</tr>
<!-- 자동 로그인 체크박스 -->
<tr>
<td>
<label for="auto-login">
<span>
<i class="fa fa-sign-in" aria-hidden="true"></i>
자동 로그인
<input type="checkbox" id="auto-login" name="isAutoLogin">
</span>
</label>
</td>
</tr>
<tr>
<td style="padding-top: 10px; text-align: center">
<p><strong>로그인하셔서 더 많은 서비스를 이용해보세요!</strong></p>
</td>
</tr>
<tr>
<td style="width: 100%; text-align: center; colspan: 2;"><input
type="submit" value="로그인" class="btn form-control tooltipstered" id="signIn-btn"
style="background-color: #343A40; margin-top: 0; height: 40px; color: white; border: 0px solid #f78f24; opacity: 0.8">
</td>
</tr>
<tr>
<td
style="width: 100%; text-align: center; colspan: 2; margin-top: 24px; padding-top: 12px; border-top: 1px solid #ececec">
<a class="btn form-control tooltipstered" href="/member/sign-up"
style="cursor: pointer; margin-top: 0; height: 40px; color: white; background-color: gray; border: 0px solid #388E3C; opacity: 0.8">
회원가입</a>
</td>
</tr>
<tr>
<td style="width: 100%; text-align: center; colspan: 2; margin-top: 24px; padding-top: 12px; border-top: 1px solid #ececec">
<a id="custom-login-btn" href="https://kauth.kakao.com/oauth/authorize?client_id=9727a2bba3b021a605228cd4978e3491&redirect_uri=http://localhost/auth/kakao&response_type=code">
<img src="//mud-kage.kakao.com/14/dn/btqbjxsO6vP/KPiGpdnsubSq3a0PHEGUK1/o.jpg" width="300"/>
</a>
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
</div>
</div>
<%@ include file="../include/footer.jsp" %>
</body>
=== 로그인 처리
== 적용 하기
쿠키(Cookie)와 세션(Session)의 차이 (+캐시(Cache)) — 슬기로운 개발생활 (tistory.com)
쿠키(Cookie)와 세션(Session)의 차이 (+캐시(Cache))
쿠키와 세션을 사용하는 이유? HTTP 프로토콜의 특징이자 약점을 보완하기 위해서 사용한다. HTTP 프로토콜의 특징 1. Connectionless 프로토콜 (비연결 지향) 클라이언트가 서버에 요청(Request)을 했을
dev-coco.tistory.com
HTTP프로토콜의 무상태성을 해결하기 위해 필요한 쿠키와 세션에 대한 설명 위의 블로그 참고 했습니다.
주석 처리 하고 jsp로 넘어간다.
로그인 안한사람이 보는 메뉴의 jstl if문 title이 아니라 test 로 수정
로그인 후 보이는 메뉴 확인
=== 로그아웃 세션을 날리면 된다.
== 인증까지 완료
== 인가 맛보기
==
referer 를 활용하여 클라이언트가 로그인 성공시 방금 접근했던 URI 로 바로 접속 될수 있도록 하기
== 인가는 내일 이어서.