사용자 기능

Q1) 사용자 등록시 입력값이 유효하지 않은 경우 예외를 발생시키는 기능을 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
입력값 : 이메일(ID), 이름, 비밀번호, 연락처
사용자 정의 에러 모델을 이용하여 에러를 리턴

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MemberInput {
    @Email(message = "이메일 형식에 맞게 입력해 주세요.")
    @NotBlank(message = "이메일은 필수 항목 입니다.")
    private String email;

    @NotBlank(message = "이름을 필수 항목 입니다.")
    private String memberName;

    @Size(min = 4, message = "비밀번호는 4자 이상 입력해야 합니다")
    @NotBlank(message = "비밀번호는 필수 항목 입니다.")
    private String password;

    @Size(max = 20, message = "연락처는 최대 20자까지 입력해야 합니다.")
    @NotBlank(message = "연락처는 필수 항목 입니다.")
    private String phone;
}

@RestController
public class ApiMemberController {
    @PostMapping("/api/member")
    public ResponseEntity<?> addMember(@RequestBody @Valid MemberInput memberInput, Errors errors) {

        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) -> {
                responseErrorList.add(ResponseError.of((FieldError) e));
            });
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }
        return ResponseEntity.ok().build();
    }
}

Q2) 사용자 정보를 입력받아서 저장하는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
입력값: 이메일(유일한  확인), 이름, 비밀번호, 연락처, 가입일(현재일시)

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String email;

    @Column
    private String memberName;

    @Column
    private String password;

    @Column
    private String phone;

    @Column
    private LocalDateTime regDate;
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;

    @PostMapping("/api/member")
    public ResponseEntity<?> addMember(@RequestBody @Valid MemberInput memberInput, Errors errors) {

        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) -> {
                responseErrorList.add(ResponseError.of((FieldError) e));
            });
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }

        memberRepository.save(Member.builder()
                .email(memberInput.getEmail())
                .memberName(memberInput.getMemberName())
                .password(memberInput.getPassword())
                .phone(memberInput.getPhone())
                .regDate(LocalDateTime.now())
                .build());

        return ResponseEntity.ok().build();
    }
}

Q3) 사용자 정보를 수정하는 API를 다음 조건에 맞게 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
사용자 정보가 없는 경우 수정하는 API를 다음 조건에 맞게 작성해 보세요.
수정정보는 연락처만 수정가능, 수정일자는 현재 날짜
에러 메세지는 "사용자 정보가 없습니다"

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String email;

    @Column
    private String memberName;

    @Column
    private String password;

    @Column
    private String phone;

    @Column
    private LocalDateTime regDate;

    @Column
    private LocalDateTime updateDate;
}
    
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberUpdate {
    @Size(max = 20, message = "연락처는 최대 20자까지 입력해야 합니다.")
    @NotBlank(message = "연락처는 필수 항목 입니다.")
    private String phone;
}

public class MemberNotFoundException extends RuntimeException{
    public MemberNotFoundException(String s){
        super(s);
    }
}

@RestControllerAdvice
public class MemberErrorHandler {

    @ExceptionHandler(MemberNotFoundException.class)
    public ResponseEntity<?> MemberNotFoundExceptionHandler(MemberNotFoundException e){
        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
    }
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;

    @PutMapping("/api/member/{id}")
    public ResponseEntity<?> updateMember(@PathVariable Long id,
                                          @RequestBody @Valid MemberUpdate memberUpdate,
                                          Errors errors) {

        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) -> {
                responseErrorList.add(ResponseError.of((FieldError) e));
            });
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }

        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다"));

        member.setPhone(memberUpdate.getPhone());
        member.setUpdateDate(LocalDateTime.now());
        memberRepository.save(member);

        return ResponseEntity.ok().build();
    }
}

Q4) 사용자 정보 조회(비밀번호, 가입일, 회원정보 수정일은 제외)의 기능을 수행하는 API를 작성해보세요.

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
29
30
31
32
33
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberResponse {
    private Long id;
    private String email;
    private String memberName;
    private String phone;
    
    public static MemberResponse of(Member member) {
        return MemberResponse.builder()
                .id(member.getId())
                .email(member.getEmail())
                .memberName(member.getMemberName())
                .phone(member.getPhone())
                .build();
    }
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;

    @GetMapping("/api/member/{id}")
    public MemberResponse getMember(@PathVariable Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));
        return MemberResponse.of(member);
    }
}

Q5) 내가 작성한 공지사항 목록에 대한 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
삭제일과 삭제자 아이디는 보안상 내리지 않음
작성자 정보를 모두 내리지 않고, 작성자의 아이디와 이름만 내림

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Notice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn
    private Member member;

    @Column
    private String title;

    @Column
    private String contents;

    @Column
    private LocalDateTime regDate;

    @Column
    private LocalDateTime updateDate;

    @Column
    private int hits;

    @Column
    private int likes;

    @Column
    private boolean deleted;

    @Column
    private LocalDateTime deletedDate;
}

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class NoticeResponse {
    private Long id;
    private Long regMemberId;
    private String regMemberName;
    private String title;
    private String contents;
    private LocalDateTime regDate;
    private LocalDateTime updateDate;
    private int hits;
    private int likes;

    public static NoticeResponse of(Notice notice) {
        return NoticeResponse.builder()
                .id(notice.getId())
                .title(notice.getTitle())
                .contents(notice.getContents())
                .regDate(notice.getRegDate())
                .regMemberId(notice.getMember().getId())
                .regMemberName(notice.getMember().getMemberName())
                .updateDate(notice.getUpdateDate())
                .hits(notice.getHits())
                .likes(notice.getLikes())
                .build();
    }
}

@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {

    Optional<List<Notice>> findByIdIn(List<Long> idList);

    int countByTitleAndContentsAndRegDateIsGreaterThanEqual(String title, String contents, LocalDateTime regDate);

    List<Notice> findByMember(Member member);
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    private final NoticeRepository noticeRepository;

    @GetMapping("/api/member/{id}/notice")
    public List<NoticeResponse> memberNotice(@PathVariable Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));

        List<Notice> noticeList = noticeRepository.findByMember(member);
        List<NoticeResponse> noticeResponseList = new ArrayList<>();
        noticeList.forEach((e) -> noticeResponseList.add(NoticeResponse.of(e)));

        return noticeResponseList;
    }
}

Q6) 사용자 등록시 이미 존재하는 이메일인 경우 예외를 발생시키는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
동일한 이메일에 가입된 회원 정보가 존재하는 경우 ExistsEmailException 발생

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    int countByEmail(String email);
}

public class ExistsEmailException extends RuntimeException {
    public ExistsEmailException(String s) {
        super(s);
    }
}



@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @ExceptionHandler(ExistsEmailException.class)
    public ResponseEntity<?> ExistsEmailException(ExistsEmailException e) {
        return new ResponseEntity<>(e.getMessage(),HttpStatus.BAD_REQUEST);
    }
    
    @PostMapping("/api/member")
    public ResponseEntity<?> addMember(@RequestBody @Valid MemberInput memberInput, Errors errors) {

        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) -> responseErrorList.add(ResponseError.of((FieldError) e)));
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }

        if (memberRepository.countByEmail(memberInput.getEmail()) > 0) {
            throw new ExistsEmailException("이미 존재하는 이메일 입니다.");
        }

        Member member = Member.builder()
                .email(memberInput.getEmail())
                .memberName(memberInput.getMemberName())
                .password(memberInput.getPassword())
                .phone(memberInput.getPhone())
                .regDate(LocalDateTime.now())
                .build();

        memberRepository.save(member);

        return ResponseEntity.ok().build();
    }
}

Q7) 사용자 비밀번호를 수정하는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
이전 비밀번호와 일치하는 경우 수정
일치하지 않는 경우 PasswordNotMatchException 발생
발생메세지는 "비밀번호가 일치하지 않습니다."

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MemberInputPassword {
    @NotBlank(message = "현재 비밀번호는 필수 항목 입니다.")
    private String password;

    @Size(min = 4, max = 20, message = "비밀번호는 4~20사이의 길이로 입력해주세요.")
    @NotBlank(message = "신규 비밀번호는 필수 항목 입니다.")
    private String newPassword;
}

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    int countByEmail(String email);

    Optional<Member> findByIdAndPassword(Long id, String password);
}

public class PasswordNotMatchException extends RuntimeException {
    public PasswordNotMatchException(String s) {
        super(s);
    }
}



public class ApiMemberController {
    private final MemberRepository memberRepository;

    @PatchMapping("/api/member/{id}/password")
    public ResponseEntity<?> updateMemberPassword(@PathVariable Long id,
                                                  MemberInputPassword memberInputPassword,
                                                  Errors errors) {
        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) ->
                    responseErrorList.add(ResponseError.of((FieldError) e)));
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }

        Member member = memberRepository.findByIdAndPassword(id, memberInputPassword.getPassword())
                .orElseThrow(() -> new PasswordNotMatchException("비밀번호가 일치하지 않습니다."));

        member.setPassword(memberInputPassword.getPassword());
        memberRepository.save(member);
        
        return ResponseEntity.ok().build();
    }
    
    @ExceptionHandler({ExistsEmailException.class, PasswordNotMatchException.class})
    public ResponseEntity<?> ExistsEmailExceptionHandler(RuntimeException e) {
        return new ResponseEntity<>(e.getMessage(),HttpStatus.BAD_REQUEST);
    }
}

Q8) 회원가입시 비밀번호를 암호화하여 저장하는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @PostMapping("/api/member")
    public ResponseEntity<?> addMember(@RequestBody @Valid MemberInput memberInput, Errors errors) {

        List<ResponseError> responseErrorList = new ArrayList<>();
        if (errors.hasErrors()) {
            errors.getAllErrors().forEach((e) -> responseErrorList.add(ResponseError.of((FieldError) e)));
            return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
        }

        if (memberRepository.countByEmail(memberInput.getEmail()) > 0) {
            throw new ExistsEmailException("이미 존재하는 이메일 입니다.");
        }

        String encryptPassword = getEncryptPassword(memberInput.getPassword());

        Member member = Member.builder()
                .email(memberInput.getEmail())
                .memberName(memberInput.getMemberName())
                .password(encryptPassword)
                .phone(memberInput.getPhone())
                .regDate(LocalDateTime.now())
                .build();

        memberRepository.save(member);

        return ResponseEntity.ok().build();
    }
    
    private String getEncryptPassword(String password) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder.encode(password);
    }
}


Q9) 사용자 회원 탈퇴 기능에 대한 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
회원정보가 존재하지 않은 경우 예외처리
만약 사용자가 등록한 공지사항이 있는 경우는 회원삭제가 되지 않음

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberInputFind {
    private String memberName;
    private String phone;
}

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    int countByEmail(String email);

    Optional<Member> findByIdAndPassword(Long id, String password);

    Optional<Member> findByMemberNameAndPhone(String memberName, String phone);
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @DeleteMapping("/api/member/{id}")
    public ResponseEntity<?> deleteMember(@PathVariable Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다"));

        try {
            memberRepository.delete(member);
        } catch (DataIntegrityViolationException e) {
            String message = "제약조건에 문제가 발생했습니다.";
            return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
        } catch (Exception e) {
            String message = "회원 탈퇴 중 문제가 발생하였습니다.";
            return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
        }
        return ResponseEntity.ok().build();
    }
}

Q10) 사용자 아이디(이메일)을 찾는 API를 작성해 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
이름과 전화번호에 해당하는 이메일을 찾는다

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @GetMapping("/api/member/find")
    public ResponseEntity<?> findMember(@RequestBody MemberInputFind memberInputFind) {
        Member member = memberRepository
                .findByMemberNameAndPhone(memberInputFind.getMemberName(), memberInputFind.getPhone())
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));

        MemberResponse memberResponse = MemberResponse.of(member);

        return ResponseEntity.ok().body(memberResponse);
    }
}

Q11) 비밀번호 초기화 요청(아이디 입력 후 전화번호로 문자 전송받음)을 수행하는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
아이디에 대한 정보 조회 
비밀번호를 초기화  이를 문자 전송 로직 호출
초기화 비밀번호는 문자열 10자로 설정

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @GetMapping("/api/member/{id}/password/reset")
    public ResponseEntity<?> resetMemberPassword(@PathVariable Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));

        // 비밀번호 초기화
        String resetPassword = getResetPassword();
        String resetEncryptPassword = getEncryptPassword(resetPassword);
        member.setPassword(resetEncryptPassword);
        memberRepository.save(member);

        String message = String.format("[%s]님의 임시 비밀번호가 [%s]로 초기화 되었습니다",
                member.getMemberName(),resetPassword);
        sendSMS(message);
        return ResponseEntity.ok().build();
    }

    private String getResetPassword() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10);
    }

    void sendSMS(String message){
        System.out.println("[문자메세지전송]");
        System.out.println(message);
    }
}

Q12) 내가 좋아요한 공지사항을 보는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class NoticeLike {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn
    private Notice notice;

    @ManyToOne
    @JoinColumn
    private Member member;
}

@Repository
public interface NoticeLikeRepository extends JpaRepository<NoticeLike, Long> {
    List<NoticeLike> findByMember(Member member);
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    private final NoticeLikeRepository noticeLikeRepository;
    
    @GetMapping("/api/member/{id}/notice/like")
    public List<NoticeLike> likeNotice(@PathVariable Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));

        return noticeLikeRepository.findByMember(member);
    }
}


사용자 인증 토큰 발행

Q1) 사용자 이메일과 비밀번호를 통해서 JWT을 발행하는 API를 작성해 보세요.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
JWT 토큰 발행시 사용자 정보가 유요하지 않을  예외 발생
사용자정보가 존재하지 않는 경우(MemberNotFoundException) 예외 발생
비밀번호가 일치하지 않는 경우 PasswordNotMatchException 예외 발생

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberLogin {
    @NotBlank(message = "이메일 항목은 필수 입니다.")
    private String email;

    @NotBlank(message = "비밀번호 항목은 필수 입니다.")
    private String password;
}

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    int countByEmail(String email);

    Optional<Member> findByIdAndPassword(Long id, String password);

    Optional<Member> findByMemberNameAndPhone(String memberName, String phone);

    Optional<Member> findByEmail(String email);
}

@UtilityClass
public class PasswordUtils {
    // 입력한 패스워드를 해시된 패스워드랑 비교하는 함수
    public static boolean equalPassword(String password, String encryptedPassword) {
        return BCrypt.checkpw(password, encryptedPassword);
    }
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @PostMapping("/api/member/login")
    public ResponseEntity<?> createToken(@RequestBody @Valid MemberLogin memberlogin) {
        Member member = memberRepository.findByEmail(memberlogin.getEmail())
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));
        if(!PasswordUtils.equalPassword(memberlogin.getPassword(),member.getPassword())){
            throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
        }
        
        return ResponseEntity.ok().build(); 
    }
}

Q2) 사용자의 이메일과 비밀번호를 통해서 JWT을 발생하는 로직을 작성해 보세요.

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
29
30
31
32
33
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberLoginToken {
    private String token;
}

@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @PostMapping("/api/member/login")
    public ResponseEntity<?> createToken(@RequestBody @Valid MemberLogin memberlogin) {
        Member member = memberRepository.findByEmail(memberlogin.getEmail())
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));
        if(!PasswordUtils.equalPassword(memberlogin.getPassword(),member.getPassword())){
            throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
        }

        // 토큰발행시점
        String token = JWT.create()
                .withExpiresAt(new Date()) //유효시간
                .withClaim("member_id", member.getId())
                .withSubject(member.getMemberName())
                .withIssuer(member.getEmail())
                .sign(Algorithm.HMAC512("zeroBase".getBytes()));
        
        return ResponseEntity.ok().body(MemberLoginToken.builder().token(token).build());
    }
}

Q3) JWT 토큰 발행시 발행 유효기간을 1개월로 저장하는 API를 작성해 보세요.

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
@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;
    
    @PostMapping("/api/member/login")
    public ResponseEntity<?> createToken(@RequestBody @Valid MemberLogin memberlogin) {
        Member member = memberRepository.findByEmail(memberlogin.getEmail())
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다."));
        if(!PasswordUtils.equalPassword(memberlogin.getPassword(),member.getPassword())){
            throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
        }

        LocalDateTime expiredDateTime = LocalDateTime.now().plusMonths(1);
        Date expiredDate = java.sql.Timestamp.valueOf(expiredDateTime);
        
        String token = JWT.create()
                .withExpiresAt(expiredDate) //유효시간
                .withClaim("member_id", member.getId())
                .withSubject(member.getMemberName())
                .withIssuer(member.getEmail())
                .sign(Algorithm.HMAC512("zeroBase".getBytes()));
        
        return ResponseEntity.ok().body(MemberLoginToken.builder().token(token).build());
    }
}

Q4) 이미 발행된 JWT 토큰을 통해서 토큰을 재발행하는 API를 작성해보세요.

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
29
30
31
32
33
34
@RestController
@RequiredArgsConstructor
public class ApiMemberController {
    private final MemberRepository memberRepository;

	@PatchMapping("/api/member/login")
    public ResponseEntity<?> refreshToken(HttpServletRequest request) {
        String token = request.getHeader("Z-TOKEN");
        String email = "";

        try {
            email = JWT.require(Algorithm.HMAC512("zeroBase".getBytes()))
                    .build()
                    .verify(token)
                    .getIssuer();
        } catch (SignatureVerificationException e) {
            throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다");
        }

        Member member = memberRepository.findByEmail(email)
                .orElseThrow(() -> new MemberNotFoundException("사용자 정보가 없습니다"));

        LocalDateTime expiredDateTime = LocalDateTime.now().plusMonths(1);
        Date expiredDate = java.sql.Timestamp.valueOf(expiredDateTime);

        String newToken = JWT.create()
                .withExpiresAt(expiredDate) //유효시간
                .withClaim("member_id", member.getId())
                .withSubject(member.getMemberName())
                .withIssuer(member.getEmail())
                .sign(Algorithm.HMAC512("zeroBase".getBytes()));
        return ResponseEntity.ok().body(MemberLoginToken.builder().token(newToken).build());
    }
}

Q5) JWT 토큰에 대한 삭제를 요청하는 API를 작성해 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
@UtilityClass
public class JWTUtils {
    private static final String KEY = "zeroBase";

    public static String getIssuer(String token) {
        return JWT.require(Algorithm.HMAC512(KEY.getBytes()))
                .build()
                .verify(token)
                .getIssuer();
    }
}


카테고리:

업데이트:

댓글남기기