# [Security] JWT ๊ตฌํ˜„ (5) - ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด JWT ํ•„ํ„ฐ ํ…Œ์ŠคํŠธ
Study Repository

[Security] JWT ๊ตฌํ˜„ (5) - ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด JWT ํ•„ํ„ฐ ํ…Œ์ŠคํŠธ

by rlaehddnd0422

๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•ด ์•ž์„œ ๊ตฌํ˜„ํ•œ JWT ๋ฐฉ์‹์˜ ์ธ์ฆ์ด ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

๐Ÿšฉ OverView

1. ์™ธ๋ถ€์™€์˜ ํ†ต์‹ ์— ์‚ฌ์šฉํ•  DTO ํด๋ž˜์Šค ์ƒ์„ฑ

2. Repository ๊ด€๋ จ ์ฝ”๋“œ ์ƒ์„ฑ

3. ๋กœ๊ทธ์ธ API, ๊ด€๋ จ ๋กœ์ง ์ƒ์„ฑ

 

๐Ÿšฉ Dto ์ƒ์„ฑ

LoginDto

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginDto {

    @NotNull
    @Size(min = 3, max = 50)
    private String username;

    @NotNull
    @Size(min = 3, max = 100)
    private String password;
}
  • ๋กœ๊ทธ์ธ์— ์‚ฌ์šฉ๋˜๋Š” ์š”์ฒญ Dto

 

MemberDto

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MemberDto {

    @NotNull
    @Size(min = 3, max = 50)
    private String username;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @NotNull
    @Size(min = 3, max = 100)
    private String password;

    @NotNull
    @Size(min = 3, max = 50)
    private String nickname;
}
  • ํšŒ์› ์ •๋ณด Dto

TokenDto

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TokenDto {
    private String token;
}
  • ํ† ํฐ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ์‘๋‹ต Dto

 

๐Ÿšฉ Repository ์ƒ์„ฑ ( Spring Data JPA )

public interface MemberRepository extends JpaRepository<Member, Long> {

    @EntityGraph(attributePaths = "authorities")
    Optional<Member> findOneWithAuthoritiesByUsername(String username); // (1)
}
  • @EntityGraph๋กœ ๋‹ค๋Œ€๋‹ค ์—ฐ๊ด€ ํ…Œ์ด๋ธ”๋„ ํ•จ๊ป˜ fetch joinํ•˜์—ฌ ์กฐํšŒํ•˜์—ฌ Username์œผ๋กœ Authority๊นŒ์ง€ ํ•จ๊ป˜ ์กฐํšŒ

 

@ManyToMany๋Š” ํŽธ๋ฆฌํ•ด ๋ณด์ด์ง€๋งŒ ์‹ค๋ฌด์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
์ด์œ  1. ๋งคํ•‘ ์ •๋ณด๋งŒ ๋„ฃ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ๋„ฃ๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์ด์œ  2. ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”(Member_Product table)์ด ์ˆจ๊ฒจ์ ธ ์žˆ์œผ๋ฏ€๋กœ ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿšฉ ๋กœ๊ทธ์ธ API ๋ฐ ๊ด€๋ จ ๋กœ์ง ์ƒ์„ฑ

๋กœ๊ทธ์ธ API ์ƒ์„ฑ

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class AuthController {
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    @PostMapping("/authenticate")
    public ResponseEntity<TokenDto> authorize(@Valid @RequestBody LoginDto loginDto) {

        // 1)usernamePasswordToken ์ƒ์„ฑ
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                loginDto.getUsername(), loginDto.getPassword());

        // 2)ํ† ํฐ๊ธฐ๋ฐ˜ authenticate() -> loadUserbyUsername()
        Authentication authentication = authenticationManagerBuilder.getObject()
                .authenticate(authenticationToken);

        // 3)Token ๊ธฐ๋ฐ˜ ๊ถŒํ•œ
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        // 4)JWT ์ƒ์„ฑ
        String jwt = tokenProvider.createToken(authentication);

        // 5)์‘๋‹ตํ—ค๋”์— jwt ์ถ”๊ฐ€
        return ResponseEntity.ok()
                .header(HttpHeaders.AUTHORIZATION, "Bearer " + jwt)
                .body(TokenDto.builder().token(jwt).build());
    }
}
  • "/api/authenticate"์˜ ์š”์ฒญ ๋ฐ”๋””์— LoginDto ์ •๋ณด๋ฅผ ๋„ฃ๊ณ  Post ์ „์†ก์‹œ authorize ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • login ์š”์ฒญ ์‹œ 
    • 1. ํ—ค๋” ์ •๋ณด๋ฅผ ํ† ๋Œ€๋กœ UsernamePasswordAuthenticationToken์„ ์ƒ์„ฑ
    • 2. ์ƒ์„ฑํ•œ ํ† ํฐ์„ ๋‹ด์•„ AuthenticationManager์—์„œ authenticate() ํ˜ธ์ถœ 
      • AuthenticationProvider์—์„œ ๋“ฑ๋กํ•œ DetailsService(๋ฐ‘์—์„œ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ loadUserByUsername ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ โžก๏ธ DB์—์„œ ์ •๋ณด ํ™•์ธ ํ›„ Authentication ๊ฐ์ฒด์— UserDetails๋ฅผ ๋‹ด์•„ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
    • 3. ๋ฆฌํ„ด๋œ Authentication ๊ฐ์ฒด๋ฅผ SecurityContext์— ๋‹ด์Šต๋‹ˆ๋‹ค. ( for ์ธ๊ฐ€ )
    • 4. Authentication ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ JWT๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • 5. ์‘๋‹ตํ—ค๋”์— JWT๋ฅผ ๋‹ด์•„ ํด๋ผ์ด์–ธํŠธ์— ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿšฉ UserDetailsService ๊ตฌํ˜„

๋‹ค์Œ์œผ๋กœ ์œ„ API์—์„œ Spring Security์˜ ์ธ์ฆ ๋ฐฉ์‹์„ ๋™์ž‘์‹œํ‚ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ UserDetailsService์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ž‘์„ฑํ•ด๋ด…์‹œ๋‹ค.

@Service
@RequiredArgsConstructor
public class MemberDetailsService implements UserDetailsService {

    private final MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<Member> member = Optional.ofNullable(memberRepository.findOneWithAuthoritiesByUsername(username).
                orElseThrow(() -> new UsernameNotFoundException(username + " -> ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")));

        return createUser(username, member.get());
    }

    private User createUser(String username, Member member) {
        if (!member.isActivated()) {
            throw new RuntimeException(username + " -> non activated!");
        }

        List<SimpleGrantedAuthority> grantedAuthorities = member.getAuthorities().stream()
                .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName()))
                .collect(toList());

        return new User(username, member.getPassword(), grantedAuthorities);
    }
}
  • authenticate() ํ˜ธ์ถœ ์‹œ ๋“ฑ๋กํ•œ DetailsService์˜ loadUserByUsername() ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • DB๋ฅผ ํ†ตํ•ด ์กฐํšŒํ•˜๊ณ , UserDetails์˜ ๊ตฌํ˜„์ฒด User๋ฅผ ๋งŒ๋“ค์–ด ๋„˜๊ฒจ์ฃผ๋„๋ก ํ•ฉ์‹œ๋‹ค.

 

๐Ÿšฉ Postman Test

์—ฌ๊ธฐ๊นŒ์ง€ ์™„๋ฃŒํ–ˆ์œผ๋ฉด ์„œ๋ฒ„๋ฅผ ํ‚ค๊ณ  postman์œผ๋กœ ํ…Œ์ŠคํŠธํ•ด๋ด…์‹œ๋‹ค.

 

์‚ฌ์ „์— data.sql์— ๋“ฑ๋กํ•œ admin ์ •๋ณด๋ฅผ ๋‹ด์•„ requestํ•ด๋ณด๋ฉด 

 

์ด๋ ‡๊ฒŒ ์ •์ƒ์ ์œผ๋กœ ํ† ํฐ์ด ๋ฐœ๊ธ‰๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์—๋Š” ๋งˆ์ง€๋ง‰์œผ๋กœ ํšŒ์› ๊ฐ€์ž…๊ณผ ๊ถŒํ•œ ๊ฒ€์ฆ๊นŒ์ง€ ํ…Œ์ŠคํŠธํ•ด๋ณด๋ฉด์„œ ๋งˆ๋ฌด๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

<์ฐธ๊ณ  ์ž๋ฃŒ>

๋ณธ ํฌ์ŠคํŒ…์€ ์ •์€๊ตฌ๋‹˜์˜ Spring Boot JWT Tutorial ๊ฐ•์˜๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

[๋ฌด๋ฃŒ] Spring Boot JWT Tutorial - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

Spring Boot, Spring Security, JWT๋ฅผ ์ด์šฉํ•œ ํŠœํ† ๋ฆฌ์–ผ์„ ํ†ตํ•ด ์ธ์ฆ๊ณผ ์ธ๊ฐ€์— ๋Œ€ํ•œ ๊ธฐ์ดˆ ์ง€์‹์„ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ํ•™์Šตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ

www.inflearn.com

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ