Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- JPA
- REST API 규칙
- git
- JPA주의사항
- 스프링 부트 공식 문서
- Error creating bean with name
- queryDSL
- 인텔리제이
- spring서버
- JoinColumn
- REST란
- jpa회원가입
- json
- 스프링 부트 기능
- Spring Spring boot 차이
- @IdClass
- ERD 작성
- 복합키
- 빈생성안됨
- jwt메서드
- uncheck Exception
- 1차캐시
- Unsatisfied dependency
- json gson 차이
- 최종 프로젝트
- github
- 스프링부트오류
- Filter
- Q 클래스
- jpa에러
Archives
- Today
- Total
Everyday Dev System
회원가입 구현하기 본문
build.gradle
// JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
application.properties - 본인의 DB 정보에 맞게 수정 필요
spring.datasource.url=jdbc:mysql://localhost:3307/auth
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
[resources] - [templates]
더보기
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="stylesheet" href="/css/style.css">
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js"></script>
<script src="/js/basic.js"></script>
<title>나만의 셀렉샵</title>
</head>
<body>
<div class="header" style="position:relative;">
<div id="login-true" style="display: none">
<div id="header-title-login-user">
<span th:text="${username}"></span> 님의
</div>
<div id="header-title-select-shop">
Select Shop
</div>
<a id="login-text" href="javascript:logout()">
로그아웃
</a>
</div>
<div id="login-false" >
<div id="header-title-select-shop">
My Select Shop
</div>
<a id="sign-text" href="/api/user/signup">
회원가입
</a>
<a id="login-text" href="/api/user/login-page">
로그인
</a>
</div>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<meta charset="UTF-8">
<title>로그인 페이지</title>
</head>
<body>
<div id="login-form">
<div id="login-title">Log into Select Shop</div>
<br>
<br>
<button id="login-id-btn" onclick="location.href='/api/user/signup'">
회원 가입하기
</button>
<form action="/api/user/login" method="post">
<div class="login-id-label">아이디</div>
<input type="text" name="username" class="login-input-box">
<div class="login-id-label">비밀번호</div>
<input type="password" name="password" class="login-input-box">
<button id="login-id-submit">로그인</button>
</form>
<div id="login-failed" style="display: none" class="alert alert-danger" role="alert">로그인에 실패하였습니다.</div>
</div>
</body>
<script>
const href = location.href;
const queryString = href.substring(href.indexOf("?")+1)
if (queryString === 'error') {
const errorDiv = document.getElementById('login-failed');
errorDiv.style.display = 'block';
}
</script>
</html>
signup.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<meta charset="UTF-8">
<title>회원가입 페이지</title>
<script>
function onclickAdmin() {
// Get the checkbox
var checkBox = document.getElementById("admin-check");
// Get the output text
var box = document.getElementById("admin-token");
// If the checkbox is checked, display the output text
if (checkBox.checked == true){
box.style.display = "block";
} else {
box.style.display = "none";
}
}
</script>
</head>
<body>
<div id="login-form">
<div id="login-title">Sign up Select Shop</div>
<form action="/api/user/signup" method="post">
<div class="login-id-label">Username</div>
<input type="text" name="username" placeholder="Username" class="login-input-box">
<div class="login-id-label">Password</div>
<input type="password" name="password" class="login-input-box">
<div class="login-id-label">E-mail</div>
<input type="text" name="email" placeholder="E-mail" class="login-input-box">
<div>
<input id="admin-check" type="checkbox" name="admin" onclick="onclickAdmin()" style="margin-top: 40px;">관리자
<input id="admin-token" type="password" name="adminToken" placeholder="관리자 암호" class="login-input-box" style="display:none">
</div>
<button id="login-id-submit">회원 가입</button>
</form>
</div>
</body>
</html>
[resources] - [static]
더보기
[css] - style.css
* {
font-family: 'Georgia', serif;
}
body {
margin: 0px;
}
.header {
height: 255px;
box-sizing: border-box;
background-color: #15aabf;
color: white;
text-align: center;
padding-top: 80px;
/*padding: 50px;*/
font-size: 45px;
font-weight: bold;
}
#header-title-login-user {
font-size: 36px;
letter-spacing: -1.08px;
}
#header-title-select-shop {
margin-top: 20px;
font-size: 45px;
letter-spacing: 1.1px;
}
#login-form {
width: 538px;
height: 710px;
margin: 70px auto 141px auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
/*gap: 96px;*/
padding: 56px 0 0;
border-radius: 10px;
box-shadow: 0 4px 25px 0 rgba(0, 0, 0, 0.15);
background-color: #ffffff;
}
#login-title {
width: 303px;
height: 32px;
/*margin: 56px auto auto auto;*/
flex-grow: 0;
font-family: SpoqaHanSansNeo;
font-size: 32px;
font-weight: bold;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: -0.96px;
text-align: left;
color: #212529;
}
#login-kakao-btn {
border-width: 0;
margin: 96px 0 8px;
width: 393px;
height: 62px;
flex-grow: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10px;
/*margin: 0 0 8px;*/
padding: 11px 12px;
border-radius: 5px;
background-color: #ffd43b;
font-family: SpoqaHanSansNeo;
font-size: 20px;
font-weight: bold;
font-stretch: normal;
font-style: normal;
color: #414141;
}
#login-id-btn {
width: 393px;
height: 62px;
flex-grow: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10px;
/*margin: 8px 0 0;*/
padding: 11px 12px;
border-radius: 5px;
border: solid 1px #212529;
background-color: #ffffff;
font-family: SpoqaHanSansNeo;
font-size: 20px;
font-weight: bold;
font-stretch: normal;
font-style: normal;
color: #414141;
}
.login-input-box {
border-width: 0;
width: 370px !important;
height: 52px;
margin: 14px 0 0;
border-radius: 5px;
background-color: #e9ecef;
}
.login-id-label {
/*width: 44.1px;*/
/*height: 16px;*/
width: 382px;
padding-left: 11px;
margin-top: 40px;
/*margin: 0 337.9px 14px 11px;*/
font-family: NotoSansCJKKR;
font-size: 16px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: -0.8px;
text-align: left;
color: #212529;
}
#login-id-submit {
border-width: 0;
width: 393px;
height: 62px;
flex-grow: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10px;
margin: 40px 0 0;
padding: 11px 12px;
border-radius: 5px;
background-color: #15aabf;
font-family: SpoqaHanSansNeo;
font-size: 20px;
font-weight: bold;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: normal;
text-align: center;
color: #ffffff;
}
#sign-text {
position:absolute;
top:48px;
right:110px;
font-size: 18px;
font-family: SpoqaHanSansNeo;
font-size: 18px;
font-weight: 500;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: 0.36px;
text-align: center;
color: #ffffff;
}
#login-text {
position:absolute;
top:48px;
right:50px;
font-size: 18px;
font-family: SpoqaHanSansNeo;
font-size: 18px;
font-weight: 500;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: 0.36px;
text-align: center;
color: #ffffff;
}
.alert-danger {
color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.alert {
width: 300px;
margin-top: 22px;
padding: 1.75rem 1.25rem;
border: 1px solid transparent;
border-radius: .25rem;
}
[js] - basic.js
let host = 'http://' + window.location.host;
$(document).ready(function () {
const auth = getToken();
if(auth === '') {
window.location.href = host + "/api/user/login-page";
} else {
$('#login-true').show();
$('#login-false').hide();
}
})
function logout() {
// 토큰 삭제
Cookies.remove('Authorization', { path: '/' });
window.location.href = host + "/api/user/login-page";
}
function getToken() {
let auth = Cookies.get('Authorization');
if(auth === undefined) {
return '';
}
return auth;
}
[controller]
더보기
HomeController.java
package com.sparta.springauth.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("username", "username");
return "index";
}
}
UserController.java
package com.sparta.springauth.controller;
import com.sparta.springauth.dto.SignupRequestDto;
import com.sparta.springauth.service.UserService;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/api")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/user/login-page")
public String loginPage() {
return "login";
}
@GetMapping("/user/signup")
public String signupPage() {
return "signup";
}
@PostMapping("/user/signup")
public String signup(SignupRequestDto requestDto) {
userService.signup(requestDto);
return "redirect:/api/user/login-page";
}
}
[service]
UserService.java
package com.sparta.springauth.service;
import com.sparta.springauth.dto.SignupRequestDto;
import com.sparta.springauth.entity.User;
import com.sparta.springauth.entity.UserRoleEnum;
import com.sparta.springauth.repository.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
// ADMIN_TOKEN -> 해당 토큰을 사용해서 관리자인지 아닌지 구분할거임.
private final String ADMIN_TOKEN = "AAABnvxRVklrnYxKZ0aHgTBcXukeZygoC";
public void signup(SignupRequestDto requestDto) {
String username = requestDto.getUsername();
String password = passwordEncoder.encode(requestDto.getPassword());// 암호화
// 회원 중복 확인
Optional<User> checkUsername = userRepository.findByUsername(username);
if (checkUsername.isPresent()) {
throw new IllegalArgumentException("중복된 사용자가 존재합니다.");
}
// email 중복확인
String email = requestDto.getEmail();
Optional<User> checkEmail = userRepository.findByEmail(email);
if (checkEmail.isPresent()) {
throw new IllegalArgumentException("중복된 Email 입니다.");
}
// 사용자 ROLE 확인
UserRoleEnum role = UserRoleEnum.USER;
if (requestDto.isAdmin()) {
if (!ADMIN_TOKEN.equals(requestDto.getAdminToken())) {
throw new IllegalArgumentException("관리자 암호가 틀려 등록이 불가능합니다.");
}
role = UserRoleEnum.ADMIN;
}
// 사용자 등록
User user = new User(username, password, email, role);
userRepository.save(user);
}
}
[repository]
UserRepository.java
package com.sparta.springauth.repository;
import com.sparta.springauth.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User,Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
[dto]
SignupRequestDto.java
package com.sparta.springauth.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SignupRequestDto {
private String username;
private String password;
private String email;
private boolean admin = false;
private String adminToken = "";
}
[Entity]
더보기
User.java
package com.sparta.springauth.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
@Enumerated(value = EnumType.STRING)
private UserRoleEnum role;
public User(String username, String password, String email, UserRoleEnum role) {
this.username = username;
this.password = password;
this.email = email;
this.role = role;
}
}
UserRoleEnum.java
package com.sparta.springauth.entity;
public enum UserRoleEnum {
USER(Authority.USER), // 사용자 권한
ADMIN(Authority.ADMIN); // 관리자 권한
private final String authority;
UserRoleEnum(String authority) {
this.authority = authority;
}
public String getAuthority() {
return this.authority;
}
public static class Authority {
public static final String USER = "ROLE_USER";
public static final String ADMIN = "ROLE_ADMIN";
}
}
결과 :
'내배캠 주요 학습 > Spring 숙련' 카테고리의 다른 글
Spring 에서 Filter란? (0) | 2023.06.20 |
---|---|
로그인 구현하기 (0) | 2023.06.19 |
JWT version 0.11.5 (0) | 2023.06.19 |
인증 - 쿠키와 세션 (1) | 2023.06.19 |
같은 타입의 Bean 객체 활용하기 (0) | 2023.06.19 |