Skip to content

Commit

Permalink
Merge pull request #22 from HandTris/#20
Browse files Browse the repository at this point in the history
νšŒμ› 관리 κΈ°λŠ₯
  • Loading branch information
seonghoo1217 authored Jun 21, 2024
2 parents 848aad5 + 2298cde commit c4adf1a
Show file tree
Hide file tree
Showing 13 changed files with 208 additions and 2 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ dependencies {
implementation group: 'org.webjars', name: 'sockjs-client', version: '1.5.1'
implementation group: 'org.webjars', name: 'stomp-websocket', version: '2.3.4'

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'

}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package jungle.HandTris.application.service;

import jungle.HandTris.domain.Member;
import jungle.HandTris.domain.exception.DuplicateNicknameException;
import jungle.HandTris.domain.exception.DuplicateUsernameException;
import jungle.HandTris.domain.exception.PasswordMismatchException;
import jungle.HandTris.domain.exception.UserNotFoundException;
import jungle.HandTris.domain.repo.MemberRepository;
import jungle.HandTris.global.exception.ErrorCode;
import jungle.HandTris.presentation.dto.request.MemberRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import jakarta.transaction.Transactional;

import java.util.Optional;

@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;

@Transactional
public Long signin (MemberRequest memberRequest) {
String username = memberRequest.username();
String password = memberRequest.password();

Member member = Optional.ofNullable(memberRepository.findByUsername(username))
.orElseThrow(() -> new UserNotFoundException());

// λΉ„λ°€λ²ˆν˜Έ 확인
if (!bCryptPasswordEncoder.matches(password, member.getPassword())) {
throw new PasswordMismatchException();
}

return member.getId();
}

@Transactional
public void signup(MemberRequest memberRequest) {
boolean usernameExists = memberRepository.existsByUsername(memberRequest.username());
boolean nicknameExists = memberRepository.existsByNickname(memberRequest.nickname());

if (nicknameExists) {
throw new DuplicateNicknameException();
}

if (usernameExists) {
throw new DuplicateUsernameException();
}

String username = memberRequest.username();
String password = memberRequest.password();
String nickname = memberRequest.nickname();

Member data = new Member(username, bCryptPasswordEncoder.encode(password), nickname);

memberRepository.save(data);
}
}
12 changes: 11 additions & 1 deletion src/main/java/jungle/HandTris/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@


import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -17,5 +22,10 @@ public class Member {

@Column(nullable = false, unique = true)
private String nickname;


public Member(String username, String password, String nickname) {
this.username = username;
this.password = password;
this.nickname = nickname;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package jungle.HandTris.domain.exception;

public class DuplicateNicknameException extends RuntimeException{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package jungle.HandTris.domain.exception;

public class DuplicateUsernameException extends RuntimeException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package jungle.HandTris.domain.exception;

public class PasswordMismatchException extends RuntimeException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package jungle.HandTris.domain.exception;

public class UserNotFoundException extends RuntimeException {
}
12 changes: 12 additions & 0 deletions src/main/java/jungle/HandTris/domain/repo/MemberRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package jungle.HandTris.domain.repo;

import jungle.HandTris.domain.Member;
import org.springframework.data.repository.Repository;

public interface MemberRepository extends Repository<Member, Long> {
Member findByUsername(String username);
boolean existsByUsername(String username);
boolean existsByNickname(String nickname);

Member save(Member member);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package jungle.HandTris.global.config.Security;

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.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {

return new BCryptPasswordEncoder();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
)
.csrf((auth) -> auth.disable()
);

return http.build();
}
}
10 changes: 9 additions & 1 deletion src/main/java/jungle/HandTris/global/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package jungle.HandTris.global.exception;

import jakarta.validation.ConstraintViolationException;
import jungle.HandTris.domain.exception.DuplicateNicknameException;
import jungle.HandTris.domain.exception.DuplicateUsernameException;
import jungle.HandTris.domain.exception.PasswordMismatchException;
import jungle.HandTris.domain.exception.UserNotFoundException;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
Expand All @@ -15,7 +19,11 @@ public enum ErrorCode {
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "μ„œλ²„μ— 였λ₯˜κ°€ μƒκ²ΌμŠ΅λ‹ˆλ‹€. κ΄€λ¦¬μžμ—κ²Œ λ¬Έμ˜ν•˜μ„Έμš”.", Set.of()),
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "μž…λ ₯ 값이 μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.",
Set.of(MethodArgumentNotValidException.class, ConstraintViolationException.class)),
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "μ§€μ›ν•˜μ§€ μ•ŠλŠ” HTTP λ©”μ„œλ“œμž…λ‹ˆλ‹€.", Set.of(HttpRequestMethodNotSupportedException.class));
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "μ§€μ›ν•˜μ§€ μ•ŠλŠ” HTTP λ©”μ„œλ“œμž…λ‹ˆλ‹€.", Set.of(HttpRequestMethodNotSupportedException.class)),
DUPLICATE_NICKNAME(HttpStatus.BAD_REQUEST, "이미 μ‘΄μž¬ν•˜λŠ” λ‹‰λ„€μž„ μž…λ‹ˆλ‹€.", Set.of(DuplicateNicknameException.class)),
DUPLICATE_USERNAME(HttpStatus.BAD_REQUEST, "이미 μ‘΄μž¬ν•˜λŠ” ID μž…λ‹ˆλ‹€.", Set.of(DuplicateUsernameException.class)),
USER_NOT_FOUND(HttpStatus.UNAUTHORIZED, "λ“±λ‘λœ μ‚¬μš©μžκ°€ μ—†μŠ΅λ‹ˆλ‹€.", Set.of(UserNotFoundException.class)),
INVALID_CREDENTIALS(HttpStatus.UNAUTHORIZED, "λΉ„λ°€λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.", Set.of(PasswordMismatchException.class));

private final HttpStatusCode status;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package jungle.HandTris.presentation.controller;

import jakarta.validation.Valid;
import jungle.HandTris.application.service.MemberService;
import jungle.HandTris.global.dto.ResponseEnvelope;
import jungle.HandTris.presentation.dto.request.MemberRequest;
import jungle.HandTris.presentation.dto.response.MemberIdDetails;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

private final MemberService memberService;

@PostMapping("/signup")
@ResponseStatus(HttpStatus.CREATED)
public ResponseEnvelope<String> signup(@RequestBody @Valid MemberRequest memberRequest) {
memberService.signup(memberRequest);

return ResponseEnvelope.of("Signup Successful");
}

@PostMapping("/signin")
public ResponseEnvelope<MemberIdDetails> signin(@RequestBody MemberRequest memberRequest) {
Long memberId = memberService.signin(memberRequest);

return ResponseEnvelope.of(new MemberIdDetails(memberId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package jungle.HandTris.presentation.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

public record MemberRequest(@NotBlank(message = "μ•„μ΄λ””λŠ” ν•„μˆ˜ μž…λ ₯ κ°’μž…λ‹ˆλ‹€.")
@Size(min = 4, max = 10, message = "μ•„μ΄λ””λŠ” μ΅œμ†Œ 4자 이상, 10자 μ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€")
@Pattern(regexp = "^[a-z0-9]+$", message = "μ•„μ΄λ””λŠ” μ•ŒνŒŒλ²³ μ†Œλ¬Έμž(a~z), 숫자(0~9)둜 κ΅¬μ„±λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.")
@Pattern(regexp = "^(?!.*admin$)", message = "admin은 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.")
String username,

@NotBlank(message = "λΉ„λ°€λ²ˆν˜ΈλŠ” ν•„μˆ˜ μž…λ ₯ κ°’μž…λ‹ˆλ‹€.")
@Size(min = 8, max = 15, message = "λΉ„λ°€λ²ˆν˜ΈλŠ” 8자 이상 15자 μ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.")
@Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[!@#$%^&*])[a-zA-Z\\d!@#$%^&*]+$", message = "λΉ„λ°€λ²ˆν˜ΈλŠ” 영문, 숫자, 특수문자λ₯Ό 각각 1개 이상 포함해야 ν•©λ‹ˆλ‹€.")
String password,

@NotBlank(message = "λ‹‰λ„€μž„μ€ ν•„μˆ˜ μž…λ ₯ κ°’μž…λ‹ˆλ‹€.")
@Size(min = 4, max = 20, message = "λ‹‰λ„€μž„μ€ μ΅œμ†Œ 4자 이상, 20자 μ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€")
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "λ‹‰λ„€μž„μ€ μ•ŒνŒŒλ²³ λŒ€μ†Œλ¬Έμžμ™€ 숫자만 μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€.")
@Pattern(regexp = "^(?!.*admin$)", message = "admin은 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.")
String nickname) {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package jungle.HandTris.presentation.dto.response;

public record MemberIdDetails(Long Id) {
}

0 comments on commit c4adf1a

Please sign in to comment.