<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
*, *:before, *:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Open Sans', Helvetica, Arial, sans-serif;
background: #ededed;
}
input, button {
border: none;
outline: none;
background: none;
font-family: 'Open Sans', Helvetica, Arial, sans-serif;
}
$
contW: 900px ;
$imgW: 260px ;
$formW: $contW - $imgW ;
$switchAT: 1.2s ;
$inputW: 260px ;
$btnH: 36px ;
$diffRatio: ( $contW - $imgW) / $contW ;
@mixin signUpActive { .cont .s--signup & { @content;
}
}
.tip {
font-size: 20px;
margin: 40px auto 50px;
text-align: center;
}
.cont {
overflow: hidden;
position: relative;
width: $contW;
height: 550px;
margin: 0 auto 100px;
background: #fff;
}
.form {
position: relative;
width: $formW;
height: 100%;
transition: transform$switchAT ease-in-out;
padding: 50px 30px 0;
}
.sub-cont {
overflow: hidden;
position: absolute;
left: $formW;
top: 0;
width: $contW;
height: 100%;
padding-left: $imgW;
background: #fff;
transition: transform$switchAT ease-in-out;
@
include
signUpActive
{
transform
:
translate3d(
$
formW
*
-1
,
0
,
0
);
}
}
button {
display: block;
margin: 0 auto;
width: $inputW;
height: $btnH;
border-radius: 30px;
color: #fff;
font-size: 15px;
cursor: pointer;
}
.img {
overflow: hidden;
z-index: 2;
position: absolute;
left: 0;
top: 0;
width: $imgW;
height: 100%;
padding-top: 360px; &: before { content : '';
position: absolute;
right: 0;
top: 0;
width: $contW;
height: 100%;
background-image:
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/sections-3.jpg');
background-size: cover;
transition: transform$switchAT ease-in-out;
}
&
:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
}
@
include signUpActive { &:before { transform:translate3d( $formW, 0, 0);
}
}
&
__text {
z-index: 2;
position: absolute;
left: 0;
top: 50px;
width: 100%;
padding: 0 20px;
text-align: center;
color: #fff;
transition: transform$switchAT ease-in-out; h2 { margin-bottom : 10px;
font-weight: normal;
}
p {
font-size: 14px;
line-height: 1.5;
}
&
.m--up { @include signUpActive { transform:translateX( $imgW *2);
}
}
&
.m--in {
transform: translateX($ imgW * -2);
@
include
signUpActive
{
transform
:
translateX(
0
);
}
}
}
&
__btn {
overflow: hidden;
z-index: 2;
position: relative;
width: 100px;
height: $btnH;
margin: 0 auto;
background: transparent;
color: #fff;
text-transform: uppercase;
font-size: 15px;
cursor: pointer; &: after { content : '';
z-index: 2;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 2px solid #fff;
border-radius: 30px;
}
span {
position: absolute;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
transition: transform$switchAT;
&.
m--in
{
transform
:
translateY(
$
btnH
*
-2
);
@
include
signUpActive
{
transform
:
translateY(
0
);
}
}
&
.m--up { @include signUpActive { transform:translateY( $btnH *2);
}
}
}
}
}
h2 {
width: 100%;
font-size: 26px;
text-align: center;
}
label {
display: block;
width: $inputW;
margin: 25px auto 0;
text-align: center; span { font-size : 12px;
color: #cfcfcf;
text-transform: uppercase;
}
}
input {
display: block;
width: 100%;
margin-top: 5px;
padding-bottom: 5px;
font-size: 16px;
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
text-align: center;
}
.forgot-pass {
margin-top: 15px;
text-align: center;
font-size: 12px;
color: #cfcfcf;
}
.submit {
margin-top: 40px;
margin-bottom: 20px;
background: #d4af7a;
text-transform: uppercase;
}
.fb-btn {
border: 2px solid #d4af7a;
color: #d4af7a; span { font-weight : bold;
color: darken(#768cb6, 20%);
}
}
.sign-in {
transition-timing-function: ease-out; @ include signUpActive {
transition-timing-function : ease-in-out;
transition-duration: $switchAT;
transform: translate3d($ formW, 0, 0);
}
}
.sign-up {
transform: translate3d($ contW * -1, 0, 0);
@
include
signUpActive
{
transform
:
translate3d(
0
,
0
,
0
);
}
}
.icon-link {
position: absolute;
left: 5px;
bottom: 5px;
width: 32px; img { width : 100%;
vertical-align: top;
}
&
--twitter
{
left
:
auto;
right
:
5px;
}
}
</style>
</head>
<body>
<h2>회원가입</h2>
<form action="/signup" method="post" id="regForm">
<div class="form sign-in" >
<div class="input-box" >
<label for="name">*아이디</label>
<input type="text" id="username" name="username"
placeholder="*아이디" oninput="noSpaceForm(this);" />
<!--중복체크 -->
<span id="idCheckMsg"></span>
</div>
<div class="input-box">
<label for="e">이메일</label>
<input type="email" id="email" name="email" placeholder="*exam@exam.com" oninput="noSpaceForm2(this);" >
<!--중복체크 -->
<span id="emailCheckMsg"></span>
</div>
<div class="input-box">
<label for="pW">비밀번호</label>
<input type="password"
id="userPw" name="password" maxlength='4'
placeholder="*비밀번호 숫자 4자리 " onkeyup="noSpaceForm(this);"
oninput="this.value = this.value.replace(/[^0-9]/g, '').replace(/(\..*)\./g, '$1');">
<p style="color: red">숫자 4자리만 입력가능</p>
</div>
<div class="input-box">
<label for="ppw">비밀번호</label>
<input type="password" id="userPwChk" name="Confirm" maxlength='4'
placeholder="*비밀번호 확인 " onkeyup="noSpaceForm(this);" class=" passConfirm()"
oninput="this.value = this.value.replace(/[^0-9]/g, '').replace(/(\..*)\./g, '$1');">
<font id="chkNotice" size="2"></font>
</div>
</div>
<button class="submit" id="btn_join" type="submit">회원가입</button>
<button class="submit" id="btn_list" type="button">처음으로</button>
</form>
</body>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
//첫 글자 공백만 사용 못 하게
/* function noSpaceForm(obj) {
if (obj.value == " ") // 공백 체크
{
//alert("해당 항목에는 공백을 사용할 수 없습니다.\n\n공백 제거됩니다.");
obj.focus();
obj.value = obj.value.replace(' ', ''); // 공백 제거
return false;
}
} */
// 공백 사용 못 하게
function noSpaceForm(obj) {
var pattern = /\s/g; // 정규표현식 패턴으로 공백 문자 전체 체크
if (pattern.test(obj.value)) {
//alert("해당 항목에는 공백을 사용할 수 없습니다.\n\n공백 제거됩니다.");
obj.focus();
obj.value = obj.value.replace(pattern, ''); // 공백 제거
}
}
function noSpaceForm2(obj) {
var emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; // 이메일 주소 형식 체크
var value = obj.value.replace(/\s/g, ''); // 공백 제거
if (!emailPattern.test(value)) {
obj.value = value;
}
}
//공백체크
$('#memberpage').on('click','#btn_join', function(){
//$("#btn_join").click(function() {
// 이메일 검사 정규식
var mailJ = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
if ($('#username').val().trim() == '') {
alert("username을 입력해주세요")
$('#username').focus();
return false;
}else if ($('#email').val().trim() == '') {
alert("email를 입력해주세요")
$('#email').focus();
return false;
// 이메일 정규식
if (mailJ.test($('#email').val())){
inval_Arr[2] = true;
} else {
inval_Arr[2] = false;
}
}else if ($('#userPw').val().trim() == '') {
alert("password를 입력해주세요")
$('#userPw').focus();
return false;
}
else if ($('#userPwChk').val().trim() == '') {
alert("password 확인 입력해주세요")
$('#userPwChk').focus();
return false;
}else if ($('#userPw').val() != $('#userPwChk').val()){
alert("비밀번호가 일치하지 않습니다.다시 확인해주세요")
return false;
}else if($('#userPw').val() == $('#userPwChk').val()){
alert("회원가입되었습니다")
return true;
}
})
//아이디 중복확인 체크
function checkIdDuplication() {
if ($("#username").val().length > 0) {
$.ajax({
url : "/idChk",
type : "post",
dataType : "json",
data : {
"username" : $("#username").val()
},
success : function(data) {
if (data == 1) {
$('#idCheckMsg').html('<span style="color:green;">중복된 아이디입니다.</span>');
//alert("중복된 아이디입니다.")
$('#username').focus();
return false;
} else if (data == 0) {
$('#idCheckMsg').html('<span style="color:red;">사용가능한 아이디입니다.</span>');
//alert("사용가능한 아이디입니다.")
$('#email').focus();
return false;
}
}
});
} else {
//alert("username을 입력해주세요")
$('#username').focus();
return false;
}
}
$(function() {
// 아이디 중복 체크를 수행하는 함수를 호출하는 이벤트 핸들러 등록
$('#username').on('blur', checkIdDuplication);
});
//이메일 중복확인 체크
function checkEmailDuplication() {
if ($("#email").val().length > 0) {
$.ajax({
url : "/emailChk",
type : "post",
dataType : "json",
data : {
"email" : $("#email").val()
},
success : function(data) {
if (data == 1) {
$('#emailCheckMsg').html('<span style="color:green;">중복된 이메일 입니다.</span>');
$('#email').focus()
return false;
} else if (data == 0) {
$('#emailCheckMsg').html('<span style="color:red;">사용가능한 이메일 입니다.</span>');
$('#password').focus()
return false;
}
}
});
}
}
$(function() {
// 아이디 중복 체크를 수행하는 함수를 호출하는 이벤트 핸들러 등록
$('#email').on('blur', checkEmailDuplication);
});
//처음으로 버튼
$('#memberpage').on('click','#btn_list', function(){
window.location.href = '/index'
})
//비밀번호 확인
$(function(){
$('#userPw').keyup(function(){
$('#chkNotice').html('');
});
$('#userPwChk').keyup(function(){
if($('#userPw').val() != $('#userPwChk').val()){
$('#chkNotice').html('비밀번호 일치하지 않음<br><br>');
$('#chkNotice').attr('color', '#f82a2aa3');
} else{
$('#chkNotice').html('비밀번호 일치함<br><br>');
$('#chkNotice').attr('color', '#199894b3');
}
});
});
</script>
</html>
@RequiredArgsConstructor
@Controller
public class UserController {
private final UserService us;
private final BCryptPasswordEncoder passwordEncoder;
// 회원가입
@RequestMapping(value = "signup", method = RequestMethod.POST)
public String signup(Member member) { // 회원 가입
// 비밀번호 암호화
String encodedPassword = passwordEncoder.encode(member.getPassword());
// 암호화 비번 다시 board에 넣음
member.setPassword(encodedPassword);
int result = us.insertmember(member);
return "redirect:/index";
}
// 아이디 중복체크
@ResponseBody
@RequestMapping(value = "/idChk", method = RequestMethod.POST)
public int idChk(Member member) throws Exception {
int result = us.idChk(member);
return result;
}
}
@RequiredArgsConstructor
@Service
public class UserServicelmpl implements UserService {
//Mybatis DB 연동
private final UserDao ud;
@Override
public int insertmember(Member member) {
int result=0;
result=ud.insertMember(member);
return result;
}
@Override
public int idChk(Member member) {
int result = ud.idChk(member);
return result;
}
}
@RequiredArgsConstructor
@Repository
public class UserDaolmpl implements UserDao {
//Mybatis DB 연동
private final SqlSession session;
@Override
public int insertMember(Member member) {
int result =0;
try {
result=session.insert("Memberinsert",member );
} catch (Exception e) {
System.out.println("다오오류"+e.getMessage());
e.printStackTrace();
}
return result;
}
@Override
public int idChk(Member member) {
int result = session.selectOne("memberidChk", member);
return result;
}
<?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.oracle.proj.dto.userMapper">
<insert id="Memberinsert" parameterType="member">
insert into member (
username
,email
,password
,role
)
values (
#{username}
,#{email}
,#{password}
,'ROLE_USER'
)
</insert>
<select id="memberidChk" resultType="int" >
SELECT COUNT(*) FROM MEMBER
WHERE username = #{username}
</select>
</mapper>
여기에 먼저 추가해준다
// Spring Security 추가
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'com.navercorp.lucy:lucy-xss:1.6.3'
implementation 'org.apache.commons:commons-text:1.9'
package com.oracle.prj.auth;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import com.oracle.prj.Dto.Member;
import lombok.RequiredArgsConstructor;
public class MemberDetails implements UserDetails {
// member 패키지에 선언해놓은 member 엔티티를 사용하기 위해 선언
private final Member dto;
public MemberDetails(Member dto) {
this.dto = dto;
}
//생성자
public Member getDto(){
return dto;
}
// member 계정의 권한을 담아두기위해
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(dto.getRole()));
return authorities;
}
// member 계정의 비밀번호를 담아두기 위해
@Override
public String getPassword() {
return dto.getPassword();
}
// member 계정의 아이디를 담아두기 위해
@Override
public String getUsername() {
return dto.getUsername();
}
// 계정이 만료되지 않았는지를 담아두기 위해 (true: 만료안됨)
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
// 계정이 잠겨있지 않았는지를 담아두기 위해 (true: 잠기지 않음)
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
// 계정의 비밀번호가 만료되지 않았는지를 담아두기 위해 (true: 만료안됨)
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
// 계정이 활성화되어있는지를 담아두기 위해 (true: 활성화됨)
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
package com.oracle.prj.auth;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.oracle.prj.Dao.UserDao;
import com.oracle.prj.Dto.Member;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class MemberDetailservice implements UserDetailsService {
private final UserDao ud;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 넘겨받은 id 로 DB 에서 회원 정보를 찾음
Member dto = ud.findByLoginId(username);
// 없을경우 에러 발생
if(dto == null)
throw new UsernameNotFoundException("아이디 혹은 비밀번호가 틀렸습니다");
// MemberDetailsImpl 에 Member 객체를 넘겨줌
return new MemberDetails(dto);
}
}
@Override
public Member findByLoginId(String username) {
Member dto = null;
try {
dto=session.selectOne("findByLoginId",username);
} catch (Exception e) {
System.out.println("다오오류"+e.getMessage());
e.printStackTrace();
}
return dto;
}
<select id="findByLoginId" parameterType="String" resultType="Member">
select username
,password
,role
,email
from member
where username =#{username}
</select>
package com.oracle.prj.auth;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MemberDetailservice memberDetailService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName(); // 사용자가 입력한 id
String passwd = (String) authentication.getCredentials(); // 사용자가 입력한 password
// 생성해둔 memberDetailService 에서 loadUserByUsername 메소드를 호출하여 사용자 정보를 가져온다.
MemberDetails details = (MemberDetails) memberDetailService.loadUserByUsername(username);
// ====================================== 비밀번호 비교 ======================================
// 사용자가 입력한 password 와 DB 에 저장된 password 를 비교한다.
// db 에 저장된 password
String dbPassword = details.getPassword();
// 암호화 방식 (BCryptPasswordEncoder) 를 사용하여 비밀번호를 비교한다.
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
if(!passwordEncoder.matches(passwd, dbPassword)) {
//System.out.println("[사용자] 비밀번호가 일치하지 않습니다.");
throw new BadCredentialsException("[사용자] 아이디 또는 비밀번호가 일치하지 않습니다.");
}
return new UsernamePasswordAuthenticationToken(details, null, details.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
package com.oracle.prj.auth;
import java.io.IOException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
public class MemberAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication ) throws IOException, ServletException {
//로그인한 username가져가기위해서 해줌
HttpSession session = request.getSession();
session.setAttribute("username", authentication.getName() );
// 로그인 성공시 이동할 페이지
setDefaultTargetUrl("/index");
// 로그인 성공시 이동할 페이지로 이동
super.onAuthenticationSuccess(request, response, authentication);
}
}
package com.oracle.prj.auth;
import java.io.IOException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
public class MemberAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication ) throws IOException, ServletException {
//로그인한 username가져가기위해서 해줌
HttpSession session = request.getSession();
session.setAttribute("username", authentication.getName() );
// 로그인 성공시 이동할 페이지
setDefaultTargetUrl("/index");
// 로그인 성공시 이동할 페이지로 이동
super.onAuthenticationSuccess(request, response, authentication);
}
}
package com.oracle.prj.auth;
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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import lombok.RequiredArgsConstructor;
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurtiyConfig {
// 생성해둔 MemberAuthenticatorProvider를 주입받는다.
// 해당 클래스로 memberDetailService 내부 로직을 수행하며
// 인증 처리도 같이 진행된다
@Autowired
CustomAuthenticationProvider cutsomAuthenticatorProvider;
// in memory 방식으로 인증 처리를 진행 하기 위해 기존엔 Override 하여 구현했지만
// Spring Security 5.7.0 버전부터는 AuthenticationManagerBuilder를 직접 생성하여
// AuthenticationManager를 생성해야 한다.
@Autowired
public void configure (AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(cutsomAuthenticatorProvider);
}
@Bean //해쉬암호화
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// 권한에 따라 허용하는 url 설정
http
.csrf().disable() //공격을 막기 위한 CSRF 토큰 검증 기능을 비활성화
.authorizeHttpRequests() //모든 HTTP 요청에 대한 인증 및 권한 부여를 설정합니다.
.requestMatchers("/login").permitAll()
//.requestMatchers("/index").permitAll() //경로로 들어오는 요청은 모든 사용자에게 허용합니다
.requestMatchers("/write").authenticated() //로그인한 사람만 보여줍니다
.anyRequest().permitAll();//경로로 들어오는 요청은 모든 사용자에게 허용합니다
//login 설정
http
.formLogin() //로그인 페이지를 자동으로 생성하고, 로그인 페이지에서 제출된 인증 정보를 처리
.loginPage("/login") // 로그인 페이지 설정
// .loginProcessingUrl("/login") // 로그인 처리 URL 설정 POST 요청 (login 창에 입력한 데이터를 처리)
.defaultSuccessUrl("/index") // 로그인 성공 후 이동할 페이지
.successHandler(new MemberAuthSuccessHandler()) // 로그인 성공 후 처리할 핸들러
.failureHandler(new MemberAuthFailureHandler());// 로그인 실패 후 처리할 핸들러
// logout 설정
http
.logout()
.logoutUrl("/logout") // 로그아웃 처리 URL 설정
.logoutSuccessUrl("/index") // 로그아웃 성공 후 이동할 페이지
.deleteCookies("JSESSIONID"); // 로그아웃 후 쿠키
return http.build();
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<!-- Latest compiled and minified CSS -->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Insert title here</title>
<style type="text/css">
.input-box{
position:relative;
margin:10px 0;
}
.input-box > input{
background:transparent;
border:none;
border-bottom: solid 1px #ccc;
padding:20px 0px 5px 0px;
font-size:14pt;
width:100%;
}
input::placeholder{
color:transparent;
}
input:placeholder-shown + label{
color:#aaa;
font-size:14pt;
top:15px;
}
input:focus + label, label{
color:#8aa1a1;
font-size:10pt;
pointer-events: none;
position: absolute;
left:0px;
top:0px;
transition: all 0.2s ease ;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
}
input:focus, input:not(:placeholder-shown){
border-bottom: solid 1px #8aa1a1;
outline:none;
}
.file-drop-area {
position: relative;
width: 200px;
height: 200px;
border: 1px dashed #ccc;
}
.file-input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.file-upload-button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.file-drop-message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.input {
position: relative;
}
.input .eyes {
position: absolute;
top: 0;
bottom: 0;
right: 0;
margin: auto 2px;
height: 30px;
font-size: 22px;
cursor: pointer;
}
table.type09 {
border-collapse: collapse;
text-align: left;
line-height: 1.5;
}
table.type09 thead th {
padding: 10px;
font-weight: bold;
vertical-align: top;
color: #369;
border-bottom: 3px solid #036;
}
table.type09 tbody th {
width: 150px;
padding: 10px;
font-weight: bold;
vertical-align: top;
border-bottom: 1px solid #ccc;
background: #f3f6f7;
}
table.type09 td {
width: 350px;
padding: 10px;
vertical-align: top;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>
<div id="memberjo"></div>
<div id="login" class="member_login" >
로그인
<form action="/login", method="post">
<div class="input-box">
<input id="username" type="text" name="username" placeholder="아이디">
<label for="id">아이디</label>
</div>
<div class="input-box">
<input id="password" type="password" name="password" placeholder="비밀번호">
<label for="pw">비밀번호</label>
</div>
<div class="member_login_btn">
<input type="button" class="btn btn-secondary" id="btn-login" onclick="button_login();" value="로그인">
<input type="button" onclick="button_join();" class="btn btn-secondary" value="회원가입">
<input type="button" id="btn_list" class="btn btn-secondary" value="처음으로">
</div>
</form>
</div>
</body>
<script type="text/javascript">
/* 회원가입 클릭시 */
function button_join() {
$('.member_login').hide();
$.ajax({
type:'GET',
url:'/memberjoin',
success:function(data){
$('#memberjo').html(data);
$('#username').focus();
}
})
}
/* 로그인클릭시 */
function button_login() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if ($('#username').val().trim() == '') {
alert("아이디를 입력해주세요")
$('#username').focus();
return false;
}else if ($('#password').val().trim() == '') {
alert("비밀번호를 입력해주세요")
$('#password').focus();
return false;
}
$.ajax({
type:'POST',
url:'/login',
data:{'username':username
,'password':password
},
success:function(data){
window.location.href = '/index';
},
//아이디 비밀번호 에러시
error: function () {
alert('아이디 또는 비밀번호를 확인하세요');
}
})
}
//처음으로 버튼
$('#memberpage').on('click','#btn_list', function(){
window.location.href = '/index'
})
</script>
</html>
🔽비밀번호 아이디 틀리면 alert창
일치시 로그인 되어짐 아이디 중복체크까지 완료