Spring Cecurity
Spring Security 란?
간단히 말하면 Spring의 보안(인증과 권한, 인가 등)을 담당하는 서블릿 필터의 집합이다.
서블릿 필터는 서블릿 실행 전에 실행되는 클래스들로 토큰 인증을 위해 컨트롤러 메서드의 첫 부분마다 인증 코드를 작성하는 고민을 해결하기 위해 서블릿 필터를 사용한다.
1. Spring Security 라이브러리 설치
implementation 'org.springframework.boot:spring-boot-starter-security'
2. 패스워드 암호화 사용 방법
* Source Code *
https://github.com/kangilbin/TodoList/blob/master/src/main/java/com/example/demo/controller/UserController.java
ackage com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.dto.ResponseDTO;
import com.example.demo.dto.UserDTO;
import com.example.demo.model.UserEntity;
import com.example.demo.security.TokenProvider;
import com.example.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("auth")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private TokenProvider tokenProvider;
// Bean으로 작성해도 됨
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@PostMapping("/signup")
public ResponseEntity<?> registerUser(@RequestBody UserDTO userDTO) {
try {
// 요청을 이용해 저장할 사용자 만들기
UserEntity user = UserEntity.builder()
.email(userDTO.getEmail())
.username(userDTO.getUsername())
// 패스워드를 인코딩하고 인코딩 값을 저장
.password(passwordEncoder.encode(userDTO.getPassword()))
.build();
// 서비스를 이용해 리포지터리에 사용자 저장
UserEntity registeredUser = userService.create(user);
UserDTO responseUserDTO = UserDTO.builder()
.email(registeredUser.getEmail())
.id(registeredUser.getId())
.username(registeredUser.getUsername())
.build();
return ResponseEntity.ok().body(responseUserDTO);
} catch (Exception e) {
// 사용자 정보는 항상 하나이므로 리스트로 만들어야 하는 ResponseDTO를 사용하지 않고 그냥 UserDTO 리턴
ResponseDTO responseDTO = ResponseDTO.builder().error(e.getMessage()).build();
return ResponseEntity.badRequest().body(responseDTO);
}
}
@PostMapping("/signin")
public ResponseEntity<?> authenticate(@RequestBody UserDTO userDTO) {
// 로그인 시 패스워드 검증
UserEntity user = userService.getByCredentials(userDTO.getEmail(), userDTO.getPassword(), passwordEncoder);
if(user != null) {
// 토큰 생성
final String token = tokenProvider.create(user);
final UserDTO responseUserDTO = UserDTO.builder()
.email(user.getEmail())
.id(user.getId())
.token(token)
.build();
return ResponseEntity.ok().body(responseUserDTO);
} else {
ResponseDTO responseDTO = ResponseDTO.builder()
.error("Login faild.")
.build();
return ResponseEntity.badRequest().body(responseDTO);
}
}
}
- BCryptPasswordEncoder : 같은 값을 인코딩하더라도 할 때마다 값이 다르고, 패스워드에 랜덤 하게 의미 없는 값을 붙여 생성한다. (이런 의미 없는 값을 보안 용어로 Salt라고 하고 Salt를 붙여 인코딩하는 것을 Salting이라고 한다.)
- encode() : BCryptPasswordEncoder의 encode() 메서드를 통해 인코딩한다.
- getByCredentials : 로그인 시 패스워드 검증을 위한 메서드 생성
3. 인코딩된 패스워드 비교 방법
로그인 시 패스워드 검증을 위한 메서드 생성
* Source Code *
https://github.com/kangilbin/TodoList/blob/master/src/main/java/com/example/demo/service/UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.example.demo.model.UserEntity;
import com.example.demo.persistence.UserRepository;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserService {
/* 기존 코드 */
public UserEntity getByCredentials(final String email, final String password, final PasswordEncoder encoder) {
final UserEntity originalUser = userRepository.findByEmail(email);
// matches 메서드를 이용해 패스워드가 같은지 확인
if(originalUser != null && encoder.matches(password, originalUser.getPassword())) {
return originalUser;
}
return null;
}
}
- matches() : BCryptPasswordEncoder는 어떤 두 값의 일치 여부를 알려주는 matches() 메서드를 제공한다.
이 메서드는 Salt(의미 없는 값)를 고려해 두 값을 비교해 일치 여부를 알려준다.
반응형
'Java' 카테고리의 다른 글
[Spring Boot] RestTemplate/WebClient 사용한 REST API 호출 방법 (0) | 2023.02.11 |
---|---|
[Spring Boot] CORS 설정 방법 (0) | 2022.10.27 |
[Spring Boot] Spring Security JWT를 사용한 토큰 인증 구현 (0) | 2022.10.25 |
JWT(JSON Web Token) 개념 및 구조 (0) | 2022.10.24 |
[Spring Boot] Rest API 개념 및 작성 방법 (0) | 2022.10.10 |