[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
'๐ Backend > Spring Security' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422