포트폴리오/ohouseClone

9.일반 로그인 만들기

가끔개발 2023. 11. 2. 00:42

0. Kanbanboard

1. 회원가입 page

  • 이메일
  • 비밀번호
  • 이름
  • 닉네임
  • 생년원일

을 입력받고 권한을 준 후 DB에저장한다.

2. Member CRUD controller

package com.portfolio.ohousev1.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.portfolio.ohousev1.entity.constant.RoleType;
import com.portfolio.ohousev1.entity.constant.RoleTypesConverter;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

@Entity
@Table(name = "member")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Member extends AuditingFields{

    @Id //보통 MemberNo 멤버 번호하고 autoincrement한다
    @Column(name = "email", unique = true)
    private String email;

    @Column
    private String Password;

    @Column
    private String nickname;

    @Column
    private String name;

    @Column
    private LocalDate birthday;

    @JsonIgnore
    @OneToMany(mappedBy = "member")
    private List<Post> posts = new ArrayList<>();

    @Convert(converter = RoleTypesConverter.class)
    @Column(nullable = false)
    private Set<RoleType> roleTypes = new LinkedHashSet<>();

    @JsonIgnore
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

    public Member(String email, String password, String nickname,
                  Set<RoleType> roleTypes,String name,LocalDate birthday){
        this.email =email;
        this.Password =password;
        this.roleTypes =roleTypes;
        this.nickname = nickname;
        this.name = name;
        this.birthday = birthday;
    }

    public static Member of(String email, String password, Set<RoleType> roleTypes,String name, String nickname, LocalDate birthday) {
        return new Member(email,password,name, nickname,birthday,null,roleTypes,null);
    }
    public  Member updatePassword(String password){
        this.Password = password;
        return this;
    }
   public String updateNickname(String name){
        this.nickname =name;
       return name;
   }
   public  Member Additional(String name, String nickname, LocalDate birthday){
        this.name =name;
        this.nickname = nickname;
        this.birthday = birthday;
        return  this;
   }
    public  static Member of( String email, String nickname, String password, Set<RoleType> roleTypes, String name, LocalDate birthday){
        return new Member( email, nickname,password,name,birthday,null,roleTypes,null);
    }
    public  static Member of( String email, String nickname, String password, Set<RoleType> roleTypes, String name, LocalDate birthday,List<Post> posts,List<Order> orders){
        return new Member(email, nickname,password,name,birthday,posts,roleTypes,orders);
    }
}

3. Member CRUD controller

@PostMapping("/signup")
    public String createMember(@ModelAttribute MemberRequest request) {
        memberService.saveMember(request.email(),request.Password(), request.dto().roleTypes(),request.name(),request.nickname(),request.birthday());
        return "redirect:/";

    }
    // 업데이트
    @PreAuthorize("isAuthenticated()")
    @GetMapping("/edit")
    public String UpdateMember(Authentication authentication, ModelMap map){
        String email = authentication.getName();
        MemberResponse Member = MemberResponse.from(memberService.getMember(email));
        map.addAttribute("member", Member);
        map.addAttribute("formStatus", FormStatus.UPDATE);
        return "user/additional";
    }
    @PreAuthorize("isAuthenticated()")
    @PostMapping("/edit")
    public String UpdateMember(Authentication authentication, @ModelAttribute MemberUpdateRequest request) {
        String email = authentication.getName();
        memberService.updateMember(email,request.dto());
        return "redirect:/";

    }
    @DeleteMapping("/{email}/delete")
    public String DeleteMember( @PathVariable String email) {
        memberService.deleteMember(email);
        return "redirect:/";

    }

4. Member CRUD Repository

@Repository
public interface MemberRepository extends JpaRepository<Member, String> {

     Optional<Member> findByEmail(String email);

    Optional<Member> findByNickname(String nickname);
    void deleteByEmail(String email);

}

5. Member CRUD Service

 @Transactional
    public MemberDto saveMember(String email,String Password,  Set<RoleType> roleTypes, String name, String nickname, LocalDate birthday) {
        roleTypes = Set.of(RoleType.USER);
        validateDuplicateMember(email);
        String encodePassword = passwordEncoder.encode(Password); // 비밀번호 해싱
        return MemberDto.from(memberRepository.save(Member.of(email,encodePassword, roleTypes,name, nickname, birthday)));
    }


    private void validateDuplicateMember(String email) {

        // 이미 가입된 이메일 주소인지 확인
        Optional<Member> existingMember = memberRepository.findByEmail(email);
        if (existingMember.isPresent()) {
            // 이미 가입된 회원이면 예외를 발생
            throw new IllegalStateException("이미 가입된 회원입니다.");
        }
    }

    @Transactional
    public String updateMember(String email, MemberDto dto) {

        Member member = memberRepository.findByEmail(email).orElseThrow(() -> new IllegalArgumentException("해당 맴버 없습니다. id" + email));
        Optional<Member> existingNickanme = memberRepository.findByNickname(dto.nickname());
        if (existingNickanme.isPresent()) {
            throw new IllegalArgumentException("이미 존재하는 닉네임입니다. 다른 닉네임을 입력해주세요.");
        } else { // 닉네임만 바꿀때
            member.updateNickname(dto.nickname());
        }
        if (dto.Password() != null && !dto.Password().isEmpty()) { // 비밀번호만 바꿀때
            String encodePassword = passwordEncoder.encode(dto.Password()); // 비밀번호 해싱
            member.updatePassword(encodePassword);
        }else { // oauth2 추가 사항
            member.Additional(dto.name(), dto.nickname(), dto.birthday());
        }
        return dto.email();


    }
    @Transactional
    public void deleteMember(String email) {
        memberRepository.deleteByEmail(email);
    }

6. MemberRequest

package com.portfolio.ohousev1.dto.member.request;

import com.portfolio.ohousev1.dto.member.MemberDto;
import com.portfolio.ohousev1.entity.constant.RoleType;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import java.time.LocalDate;
import java.util.Set;


public record MemberRequest(
        @NotEmpty(message = "이메일 필수입니다.")
        @Email(message = "올바른 이메일 주소를 입력하세요.")
        String email,
        Long MemberNo,
        @NotEmpty(message = "비밀번호 필수입니다.")
        @Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}$", message = "비밀번호는 최소 8자 이상이어야 하며, 대문자, 소문자, 숫자를 포함해야 합니다.")
        String Password,
        @NotEmpty(message = "이름 필수입니다.")
        String name,
        @NotEmpty(message = "닉네임 필수입니다.")
        String nickname,
        @NotEmpty(message = "생일은 필수입니다.")
        LocalDate birthday
) {


    public static MemberRequest of(String email, Long MemberNo,String Password, String name, String nickname, LocalDate birthday) {
        return new MemberRequest(email,MemberNo, Password,name,nickname,birthday);
    }
    public MemberDto dto(){
        Set<RoleType> roleTypes = Set.of(RoleType.USER);
        return MemberDto.of(email,Password,roleTypes,name,nickname,birthday);
    }
}

7.MemberUpdateRequest

package com.portfolio.ohousev1.dto.member.request;

import com.portfolio.ohousev1.dto.member.MemberDto;
import com.portfolio.ohousev1.entity.constant.RoleType;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;

import java.time.LocalDate;
import java.util.Set;

public record MemberUpdateRequest(
        String email,
        @NotEmpty(message = "비밀번호 필수입니다.")
        @Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}$", message = "비밀번호는 최소 8자 이상이어야 하며, 대문자, 소문자, 숫자를 포함해야 합니다.")
        String Password,
        @NotEmpty(message = "이름 필수입니다.")
        String name,
        @NotEmpty(message = "닉네임 필수입니다.")
        String nickname,
        @NotEmpty(message = "생일은 필수입니다.")
        LocalDate birthday
) {
    public static MemberUpdateRequest of(String email,String Password,String name, String nickname, LocalDate birthday) {
        return new MemberUpdateRequest(email,Password,name, nickname, birthday);
    }
    public MemberDto dto(){
        Set<RoleType> roleTypes = Set.of(RoleType.USER);
        return MemberDto.of(email,Password,roleTypes,name,nickname,birthday);
    }
}

8. MemberDto

package com.portfolio.ohousev1.dto.member;

import com.portfolio.ohousev1.entity.Member;
import com.portfolio.ohousev1.entity.constant.RoleType;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;


public record MemberDto (
        String email,
        String Password,
        Set<RoleType> roleTypes,
        String name,
        String nickname,
        LocalDate birthday,
        LocalDateTime createdAt,
        LocalDateTime modifiedAt
)
{



    public  static MemberDto of(String email, String Password,Set<RoleType> roleTypes,String name, String nickname, LocalDate birthday){
        return new MemberDto(email,Password, roleTypes,name,nickname,birthday,null,null);
    }
    public  static MemberDto of(String email, String Password,Set<RoleType> roleTypes, String nickname){
        return new MemberDto(email,Password,roleTypes,null,nickname,null,null,null);
    }
    public  static MemberDto of(String email,String Password,Set<RoleType> roleTypes, String name, String nickname,LocalDate birthday, LocalDateTime createdAt, LocalDateTime modifiedAt){
        return new MemberDto(email,Password,roleTypes,name,nickname,birthday,createdAt,modifiedAt);
    }
    public static MemberDto of(MemberDto memberDto ) {
        return new MemberDto(memberDto.email, memberDto.Password,memberDto.roleTypes, memberDto.name, memberDto.nickname, memberDto.birthday, memberDto.createdAt, memberDto.modifiedAt);
    }
    public static MemberDto from(Member entity){
        return new MemberDto(
                entity.getEmail(),
                entity.getPassword(),
                entity.getRoleTypes(),
                entity.getName(),
                entity.getNickname(),
                entity.getBirthday(),
                entity.getCreatedAt(),
                entity.getModifiedAt()
        );
    }



    public Member toEntity() {
        return Member.of(
                email,
                Password,
                roleTypes,
                name,
                nickname,
                birthday
        );
    }

}

9. Member

package com.portfolio.ohousev1.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.portfolio.ohousev1.entity.constant.RoleType;
import com.portfolio.ohousev1.entity.constant.RoleTypesConverter;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

@Entity
@Table(name = "member")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Member extends AuditingFields{

    @Id
    @Column(name = "email", unique = true)
    private String email;

    @Column
    private String Password;

    @Column
    private String nickname;

    @Column
    private String name;

    @Column
    private LocalDate birthday;

    @JsonIgnore
    @OneToMany(mappedBy = "member")
    private List<Post> posts = new ArrayList<>();

    @Convert(converter = RoleTypesConverter.class)
    @Column(nullable = false)
    private Set<RoleType> roleTypes = new LinkedHashSet<>();

    @JsonIgnore
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

    public Member(String email, String password, String nickname,
                  Set<RoleType> roleTypes,String name,LocalDate birthday){
        this.email =email;
        this.Password =password;
        this.roleTypes =roleTypes;
        this.nickname = nickname;
        this.name = name;
        this.birthday = birthday;
    }

    public static Member of(String email, String password, Set<RoleType> roleTypes,String name, String nickname, LocalDate birthday) {
        return new Member(email,password,name, nickname,birthday,null,roleTypes,null);
    }
    public  Member updatePassword(String password){
        this.Password = password;
        return this;
    }
   public String updateNickname(String name){
        this.nickname =name;
       return name;
   }
   public  Member Additional(String name, String nickname, LocalDate birthday){
        this.name =name;
        this.nickname = nickname;
        this.birthday = birthday;
        return  this;
   }
    public  static Member of( String email, String nickname, String password, Set<RoleType> roleTypes, String name, LocalDate birthday){
        return new Member( email, nickname,password,name,birthday,null,roleTypes,null);
    }
    public  static Member of( String email, String nickname, String password, Set<RoleType> roleTypes, String name, LocalDate birthday,List<Post> posts,List<Order> orders){
        return new Member(email, nickname,password,name,birthday,posts,roleTypes,orders);
    }
}

10. SecurityConfig

package com.portfolio.ohousev1.config;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig {

    private final OAuth2UserService oAuth2UserService;

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

        http
                .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        .requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
                .csrf((csrf) -> csrf
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                        .ignoringRequestMatchers(new AntPathRequestMatcher("/mysql/**")))
                .headers((headers) -> headers
                        .addHeaderWriter(new XFrameOptionsHeaderWriter(
                                XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)));
        // login 설정
        http
                .oauth2Login(httpSecurityOAuth2LoginConfigurer -> httpSecurityOAuth2LoginConfigurer
                        .loginPage("/login")
                        .userInfoEndpoint()
                        .userService(oAuth2UserService));

        http
                .formLogin((formLogin) -> formLogin
                        .loginPage("/login")
                        .usernameParameter("email")    // login에 필요한 id 값을 email로 설정 (default는 username)
                        .passwordParameter("password")// login에 필요한 password 값을 password(default)로 설정
                        .defaultSuccessUrl("/"));    // login에 성공하면 /로 redirect

        http
                .logout((logout) -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/members/logout"))
                        .permitAll()
                        .logoutSuccessUrl("/")// logout에 성공하면 /로 redirect
                        .invalidateHttpSession(true));

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService(MemberService memberService) {
        return email -> memberService
                .searchEmail(email)
                .map(PostPrincipal::from)
                .orElseThrow(() -> new UsernameNotFoundException("유저를 찾을 수 없습니다 - username: " + email));
    }
}

11. SequenceDiagram

https://github.com/nodwon/OhouseV1

 

GitHub - nodwon/OhouseV1: 지금까지 공부한것을 기반으로 포트폴리오 제작

지금까지 공부한것을 기반으로 포트폴리오 제작. Contribute to nodwon/OhouseV1 development by creating an account on GitHub.

github.com