팀 프로젝트가 끝났다. 나는 네이버 로그인을 마지막에 시도했지만, 뭔가 다 됐는데 안됐다.
ouath 생활코딩 영상을보고 좀 더 이해를 해야될거같다. 회고는 여기에 작성을 했다
https://kiseokkm.tistory.com/88
팀원들 모두 열심히 해주고, 소통도 잘 됐다. 온라인상에서 원래는 회의나 대화를할때 거의 캠을 끄고 진행을 하는데
이번 조는 다들 적극적이고 매우 좋았다. 리더가 미숙했지만, 모두가 다 리더처럼 잘 도와주셨다.
발표할때 다른조들도 보니깐 열심히 잘 한거같다. 모두 같이 성장하고있는거 보니깐 매우 좋다.
일단 네이버 로그인 코드다. 아직 구현은 하지 못했다.
WebSecurityConfig
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf( (csrf) -> csrf.disable());
http.sessionManagement( (sessionManagement) -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.authorizeHttpRequests( (authorizeHttpRequests) ->
authorizeHttpRequests
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.requestMatchers("/users/login", "/users/signup", "/api/users/refresh", "/users/login/kakao/**", "/users/login/naver/**").permitAll()
.requestMatchers(HttpMethod.GET, "/orders", "/stores").permitAll()
.requestMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
);
Controller를 그냥 user에 넣어도 됐는데, 일단 만들어놨다. 추후에 바꿀예정이다
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class NaverLoginController {
private final NaverLoginService naverLoginService;
@GetMapping("/login/naver")
public ResponseEntity<StatusCommonResponse> naverLogin(@RequestParam String code, @RequestParam String state, HttpServletResponse response) throws Exception {
naverLoginService.loginWithNaver(code, state, response);
StatusCommonResponse commonResponse = new StatusCommonResponse(200, "네이버 로그인 성공");
return ResponseEntity.ok().body(commonResponse);
}
}
Service
@Slf4j
@Service
@RequiredArgsConstructor
public class NaverLoginService {
private final UserRepository userRepository;
private final JwtUtil jwtUtil;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private final PasswordEncoder passwordEncoder;
public void loginWithNaver(String code, String state, HttpServletResponse response) throws Exception {
String accessToken = getAccessToken(code, state);
NaverUserInfoDto naverUserInfo = getNaverUserInfo(accessToken);
User naverUser = registerNaverUserIfNeeded(naverUserInfo);
String jwtAccessToken = jwtUtil.generateAccessToken(naverUser.getUserId(), naverUser.getUserName(), naverUser.getUserAuth());
String jwtRefreshToken = jwtUtil.generateRefreshToken(naverUser.getUserId(), naverUser.getUserName(), naverUser.getUserAuth());
ResponseCookie refreshTokenCookie = jwtUtil.generateRefreshTokenCookie(jwtRefreshToken);
naverUser.updateRefreshToken(jwtRefreshToken);
userRepository.save(naverUser);
response.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + jwtAccessToken);
response.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json;charset=UTF-8");
}
private String getAccessToken(String code, String state) throws Exception {
URI uri = UriComponentsBuilder
.fromUriString("https://nid.naver.com/oauth2.0/token")
.queryParam("grant_type", "authorization_code")
.queryParam("client_id", "8mWUC54LGL2OeCnJ7vtZ")
.queryParam("client_secret", "c_kAL5shZd")
.queryParam("code", code)
.queryParam("state", state)
.build()
.toUri();
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
JsonNode jsonNode = objectMapper.readTree(response.getBody());
JsonNode accessTokenNode = jsonNode.get("access_token");
if (accessTokenNode == null) {
log.error("Failed to retrieve access token: {}", response.getBody());
throw new IllegalStateException("Failed to retrieve access token");
}
return accessTokenNode.asText();
}
private NaverUserInfoDto getNaverUserInfo(String accessToken) throws Exception {
URI uri = UriComponentsBuilder
.fromUriString("https://openapi.naver.com/v1/nid/me")
.build()
.toUri();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
JsonNode jsonNode = objectMapper.readTree(response.getBody()).get("response");
if (jsonNode == null || jsonNode.get("name") == null || jsonNode.get("email") == null) {
throw new IllegalStateException("네이버 사용자 정보 응답에서 필수 필드가 누락");
}
String name = jsonNode.get("name").asText();
String email = jsonNode.get("email").asText();
return new NaverUserInfoDto(name, email);
}
private User registerNaverUserIfNeeded(NaverUserInfoDto naverUserInfo) {
String email = naverUserInfo.getEmail();
Optional<User> optionalUser = userRepository.findByEmail(email);
User naverUser;
if (optionalUser.isPresent()) {
naverUser = optionalUser.get();
} else {
String password = passwordEncoder.encode(UUID.randomUUID().toString());
naverUser = new User(
email,
password,
naverUserInfo.getName(),
email,
UserStatus.ACTIVE,
UserAuth.USER,
null,
null
);
userRepository.save(naverUser);
}
return naverUser;
}
}
dto
@Getter
@NoArgsConstructor
public class NaverUserInfoDto {
private String name;
private String email;
public NaverUserInfoDto(String name, String email) {
this.name = name;
this.email = email;
}
}
User에도 추가 해줬다.
/**
* 사용자 엔티티 클래스 데이터베이스의 사용자 정보를 나타내는 클래스
*/
@Entity
@Getter
@NoArgsConstructor
@Table(name = "users")
public class User extends TimeStamp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String userId;
@Column(nullable = false)
private String password;
@Column(nullable = false, length = 50)
private String userName;
@Column(nullable = false, unique = true, length = 50)
private String email;
@Column(length = 100)
private String intro;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserAuth userAuth;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserStatus userStatus;
@Column(unique = true)
private String refreshToken;
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE)
private List<Menu> menu = new ArrayList<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE)
private List<Review> comments = new ArrayList<>();
private Long kakaoId;
private Long naverId;
@ElementCollection(fetch = FetchType.EAGER) // FetchType 설정 추가
@CollectionTable(name = "past_passwords", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "password")
private List<String> pastPasswords = new ArrayList<>();
public User(SignupRequestDto requestDto, UserStatus userStatus, UserAuth userAuth) {
this.userId = requestDto.getUserId();
this.password = requestDto.getPassword();
this.userName = requestDto.getUserName();
this.email = requestDto.getEmail();
this.intro = requestDto.getIntro();
this.userStatus = userStatus;
this.userAuth = userAuth;
this.pastPasswords.add(this.password);
}
public User(String userId, String password, String userName, String email, UserStatus userStatus, UserAuth userAuth, Long kakaoId) {
this.userId = userId;
this.password = password;
this.userName = userName;
this.email = email;
this.userStatus = userStatus;
this.userAuth = userAuth;
this.kakaoId = kakaoId;
this.pastPasswords.add(this.password);
}
public User(String userId, String password, String userName, String email, UserStatus userStatus, UserAuth userAuth, Long kakaoId, Long naverId) {
this.userId = userId;
this.password = password;
this.userName = userName;
this.email = email;
this.userStatus = userStatus;
this.userAuth = userAuth;
this.kakaoId = kakaoId;
this.naverId = naverId;
this.pastPasswords.add(this.password);
}
public void updateUserStatus(UserStatus userStatus) {
this.userStatus = userStatus;
}
public void updateRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public void updatePassword(String newPassword) {
if (this.pastPasswords.size() >= 3) {
this.pastPasswords.remove(0);
}
this.pastPasswords.add(newPassword);
this.password = newPassword;
}
public void encryptionPassword(String password) {
this.password = password;
}
public void updateUserName(String userName) {
this.userName = userName;
}
public void updateIntro(String intro) {
this.intro = intro;
}
public void updateProfile(AdminUserProfileRequestDto requestDto) {
this.userName = requestDto.getUserName();
this.intro = requestDto.getIntro();
}
public void updateAuth(UserAuth userAuth) {
this.userAuth = userAuth;
}
public User kakaoIdUpdate(Long kakaoId) {
this.kakaoId = kakaoId;
return this;
}
public User naverIdUpdate(Long naverId) {
this.naverId = naverId;
return this;
}
}
properties에도 추가를 해줬다.
spring.security.oauth2.client.registration.naver.client-id=8mWUC54LGL2OeCnJ7vtZ
spring.security.oauth2.client.registration.naver.client-secret=c_kAL5shZd
spring.security.oauth2.client.registration.naver.scope=name,email
spring.security.oauth2.client.registration.naver.client-name=Naver
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8080/login/oauth2/code/naver
spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user-name-attribute=response
최종코드 : https://github.com/GreedyPeople/GreedyPeople
'TIL' 카테고리의 다른 글
TIL - 2024/06/28 (0) | 2024.06.28 |
---|---|
TIL - 2024/06/26 (0) | 2024.06.26 |
TIL - 2024/06/24 (0) | 2024.06.24 |
TIL - 2024/06/21 (0) | 2024.06.21 |
TIL - 2024/06/20 (0) | 2024.06.20 |