
login.html: Username과 Password 입력하는 로그인 페이지 HTML 생성login.scss: login.html의 SCSSlogin.css: login.html의 CSSlogin.php: 로그인 성공/실패 처리loginSuccess.php: 로그인 성공시 나타낼 페이지 (username을 동적으로 받아서 해당 페이지에 출력할 예정)
login.html▷ Username과 Password 입력하는 로그인 HTML 페이지
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Page</title>
<script src="https://kit.fontawesome.com/242c7614be.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="./css/login.css">
</head>
<body>
<div class="login">
<div class="login__forms">
<!-- login form -->
<form action="./php/login.php" method="POST" class="login__register block" id="login-in"> <h1 class="login__title">Sign In</h1>
<div class="login__box">
<i class="fas fa-user login__icon"></i>
<input type="text" placeholder="Username" class="login__input" name="username">
</div>
<div class="login__box">
<i class="fas fa-lock login__icon"></i>
<input type="password" placeholder="Password" class="login__input" name="password">
</div>
<a href="#" class="login__forgot">Forgot Password?</a>
<a href="#" class="login__button">Sign In</a>
<div>
<span class="login__account login__account--account">Don't Have an Account?</span>
<span class="login__signin login__signin--signup" id="sign-up">Sign Up</span>
</div>
</form>
<!-- create account form -->
<form action="" class="login__create none" id="login-up">
<h1 class="login__title">Create Account</h1>
<div class="login__box">
<i class="fas fa-user login__icon"></i>
<input type="text" placeholder="Username" class="login__input">
</div>
<div class="login__box">
<i class="fa-solid fa-at login__icon"></i>
<input type="email" placeholder="Email" class="login__input">
</div>
<div class="login__box">
<i class="fas fa-lock login__icon"></i>
<input type="password" placeholder="Password" class="login__input">
</div>
<a href="#" class="login__button">Sign Up</a>
<div>
<span class="login__account login__account--account">Already have an Account?</span>
<span class="login__signup login__signup--signup" id="sign-in">Sign In</span>
</div>
<div class="login__social">
<a href="#" class="login__social--icon"><i class="fab fa-facebook-f"></i></a>
<a href="#" class="login__social--icon"><i class="fab fa-x-twitter"></i></a>
<a href="#" class="login__social--icon"><i class="fab fa-google"></i></a>
<a href="#" class="login__social--icon"><i class="fab fa-github"></i></a>
</div>
</form>
</div>
</div>
<script src="./js/login.js"></script>
</body>
</html>
login.scss▷ login.html의 SCSS
// 1. 변수 정의
$color-primary: #4AD395;
$color-primary-hover: #65bf97;
$color-dark: #23004d;
$color-light: #a49eac;
$color-bg: #f2f2f2;
$font: 'Open Sans', sans-serif;
$font-size-normal: 0.938rem;
$font-size-small: 0.813rem;
$font-size-big: 1.5rem;
*, ::before, ::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: $font;
font-size: $font-size-normal;
color: $color-dark;
}
h1 {
margin: 0;
}
a {
text-decoration: none;
}
// sign-in, sign-up 레이아웃
.login {
display: grid;
place-items: center;
height: 100vh;
padding: 1.5rem;
&__forms {
width: 100%;
max-width: 348px;
background-color: $color-bg;
padding: 2rem 1rem;
border-radius: 1rem;
text-align: center;
box-shadow: 0 8px 20px rgba($color-dark, 0.2);
animation: animateLogin 0.4s;
}
&__title {
font-size: $font-size-big;
margin-bottom: 2rem;
}
&__box {
display: grid;
grid-template-columns: max-content 1fr;
column-gap: 0.5rem;
padding: 1.125rem 1rem;
background-color: #fff;
margin-top: 1rem;
border-radius: 0.5rem;
}
&__icon {
font-size: $font-size-big;
color: $color-primary;
}
&__input {
border: none;
outline: none;
font-size: $font-size-normal;
font-weight: 700;
color: $color-dark;
width: 100%;
&::placeholder {
color: $color-light;
}
}
&__forgot {
display: block;
width: max-content;
margin-left: auto;
margin-top: 0.5rem;
font-size: $font-size-small;
font-weight: 600;
color: $color-light;
}
&__button {
display: block;
padding: 1rem;
margin: 2rem 0;
width:100%;
background-color: $color-primary;
color: #fff;
font-weight: 600;
text-align: center;
border-radius: 0.5rem;
border:none;
transition: 0.3s;
&:hover {
background-color: $color-primary-hover;
}
}
&__account,
&__signin,
&__signup {
font-weight: 600;
font-size: $font-size-small;
&--account {
color: $color-dark;
}
&--signup {
color: $color-primary;
cursor: pointer;
}
}
&__social {
margin-top: 2rem;
&--icon {
font-size: $font-size-big;
color: $color-dark;
margin: 0 1rem;
}
}
}
.block {
display: block;
}
.none {
display: none;
}
@keyframes animateLogin {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
login.css▷ login.html의 CSS
*, ::before, ::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: "Open Sans", sans-serif;
font-size: 0.938rem;
color: #23004d;
}
h1 {
margin: 0;
}
a {
text-decoration: none;
}
.login {
display: grid;
place-items: center;
height: 100vh;
padding: 1.5rem;
}
.login__forms {
width: 100%;
max-width: 348px;
background-color: #f2f2f2;
padding: 2rem 1rem;
border-radius: 1rem;
text-align: center;
box-shadow: 0 8px 20px rgba(35, 0, 77, 0.2);
animation: animateLogin 0.4s;
}
.login__title {
font-size: 1.5rem;
margin-bottom: 2rem;
}
.login__box {
display: grid;
grid-template-columns: max-content 1fr;
-moz-column-gap: 0.5rem;
column-gap: 0.5rem;
padding: 1.125rem 1rem;
background-color: #fff;
margin-top: 1rem;
border-radius: 0.5rem;
}
.login__icon {
font-size: 1.5rem;
color: #4AD395;
}
.login__input {
border: none;
outline: none;
font-size: 0.938rem;
font-weight: 700;
color: #23004d;
width: 100%;
}
.login__input::-moz-placeholder {
color: #a49eac;
}
.login__input::placeholder {
color: #a49eac;
}
.login__forgot {
display: block;
width: -moz-max-content;
width: max-content;
margin-left: auto;
margin-top: 0.5rem;
font-size: 0.813rem;
font-weight: 600;
color: #a49eac;
}
.login__button {
display: block;
padding: 1rem;
margin: 2rem 0;
width: 100%;
background-color: #4AD395;
color: #fff;
font-weight: 600;
text-align: center;
border-radius: 0.5rem;
border:none;
transition: 0.3s;
}
.login__button:hover {
background-color: #65bf97;
}
.login__account, .login__signin, .login__signup {
font-weight: 600;
font-size: 0.813rem;
}
.login__account--account, .login__signin--account, .login__signup--account {
color: #23004d;
}
.login__account--signup, .login__signin--signup, .login__signup--signup {
color: #4AD395;
cursor: pointer;
}
.login__social {
margin-top: 2rem;
}
.login__social--icon {
font-size: 1.5rem;
color: #23004d;
margin: 0 1rem;
}
.block {
display: block;
}
.none {
display: none;
}
@keyframes animateLogin {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
login.php▷ 로그인 성공/실패 처리
• 로그인 성공 시:
↳success.php페이지로 이동하면서, 인코딩된 username을 URL에 포함시켜 전달.
• 로그인 실패 시:
↳ PHP 안에서 JavaScript 코드를 출력해서,
"로그인 실패 !" 알림창을 띄우고, 알림창 닫으면 다시 로그인 페이지(login.html)로 자동 이동.
<?php
$username = $_POST['username'];
$pw = $_POST['password'];
//디버깅(테스트)
//echo "Username: " . htmlspecialchars($username) . "<br>";
//echo "Password: " . htmlspecialchars($pw);
if($username == 'admin' && $pw == 'admin1234'){
$username_urlencoded = urlencode($username);
header("Location: loginSuccess.php?username=$username_urlencoded");
exit();
}else{
//로그인 실패한 경우
echo "<script> alert('로그인 정보가일치하지 않습니다.');window.location.href='/project-folder/login.html'; </script>";
}
?>
loginSuccess.php▷ 로그인 성공시 나타낼 페이지(username을 동적으로 받아서 페이지에서 출력)
↳ 현재 username은 admin.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Success!</title>
<style>
.container{
display:grid;
place-items:center;
height: 100vh;
padding: 1.5rem;
}
.contents{
width:100%;
max-width:348px;
background-color:#f2f2f2;
padding:2rem 1rem;
border-radius:1rem;
text-align:center;
box-shadow: 0 8px 20px rgba(35, 0, 77, 0.2);
}
.welcome,.username{
font-weight: 600;
font-size:1.5rem;
}
</style>
</head>
<body>
<div class="container">
<div class="contents">
<div class="welcome">Welcome !</div>
<div class="username"><?php echo $_GET['username'];?></div>
</div>
</div>
</body>
</html>
⚠️ 문제점
→ URL에?username=admin처럼 사용자 정보인 username이 그대로 보이는 방식은 보안의 문제가 있다...