Skip to content

Commit

Permalink
Feat : DIG-65 카카오 소셜 로그인 구현 방법 추가
Browse files Browse the repository at this point in the history
- 인가코드를 프론트에서 건네받아 토큰 요청하는 흐름으로 변경
- userRepository 조회로직 직접 조회로 변경 (후에 삭제한 회원 로직 추가해야)
- loginDto 값 조정 및 패키지 이동
  • Loading branch information
dunowljj committed Nov 13, 2023
1 parent 4cb820f commit e875414
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 46 deletions.
44 changes: 24 additions & 20 deletions src/main/java/com/ogjg/daitgym/config/security/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.ogjg.daitgym.config.security;

import com.ogjg.daitgym.config.security.jwt.authentication.JwtAuthenticationProvider;
import com.ogjg.daitgym.config.security.jwt.filter.JwtAccessTokenAuthenticationFilter;
import com.ogjg.daitgym.config.security.jwt.filter.JwtRefreshTokenAuthenticationFilter;
import com.ogjg.daitgym.config.security.jwt.handler.JwtAuthenticationEntryPoint;
import com.ogjg.daitgym.config.security.oauth.CustomOAuth2UserService;
import com.ogjg.daitgym.domain.Role;
Expand All @@ -15,10 +17,12 @@
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsUtils;
Expand All @@ -45,16 +49,17 @@ public class SecurityConfig {

private final List<String> permitJwtUrlList = new ArrayList<>(
List.of(

"/",
"/favicon.ico",
"/login/oauth2/callback/kakao.*",
"/login/oauth2/code/.*",
"/oauth2/authorization/.*",
"/api/users/token",
"/api/token/new",
"/health",
"/ws/.*",
"/chat/.*"

"/chat/.*",
"/h2-console/.*"
));

@Bean
Expand All @@ -68,16 +73,15 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.frameOptions((frameOptionsConfig) -> frameOptionsConfig.sameOrigin())
)
)
// .addFilterBefore(jwtAccessTokenAuthenticationFilter(), OAuth2AuthorizationRequestRedirectFilter.class)
// .addFilterAfter(jwtRefreshTokenAuthenticationFilter(), JwtAccessTokenAuthenticationFilter.class)
.addFilterBefore(jwtAccessTokenAuthenticationFilter(), OAuth2AuthorizationRequestRedirectFilter.class)
.addFilterAfter(jwtRefreshTokenAuthenticationFilter(), JwtAccessTokenAuthenticationFilter.class)
.authorizeHttpRequests(
authorize -> authorize
.requestMatchers(CorsUtils::isPreFlightRequest)
.permitAll()
.requestMatchers("/**").permitAll()
.requestMatchers("/api/admins/**").hasRole(Role.ADMIN.name())
.requestMatchers("/api/trainers/**").hasRole(Role.TRAINER.name())
.requestMatchers("/api/profiles/**").hasRole(Role.USER.name())
.requestMatchers(new AntPathRequestMatcher("/api/admins/**")).hasRole(Role.ADMIN.name())
.requestMatchers(new AntPathRequestMatcher("/api/trainers/**")).hasRole(Role.TRAINER.name())
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll()
.anyRequest().authenticated()
).exceptionHandling((exceptionHandle) -> exceptionHandle
.accessDeniedHandler(accessDeniedHandler)
Expand Down Expand Up @@ -115,17 +119,17 @@ public CorsConfigurationSource corsConfigurationSource() {
public AuthenticationManager authenticationManager() throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
//
// @Bean
// public JwtAccessTokenAuthenticationFilter jwtAccessTokenAuthenticationFilter() throws Exception {
// authenticationManagerBuilder.authenticationProvider(jwtAuthenticationProvider());
// return new JwtAccessTokenAuthenticationFilter(authenticationManager(), jwtAuthenticationEntryPoint(), permitJwtUrlList);
// }
//
// @Bean
// public JwtRefreshTokenAuthenticationFilter jwtRefreshTokenAuthenticationFilter() throws Exception {
// return new JwtRefreshTokenAuthenticationFilter(authenticationManager(), jwtAuthenticationEntryPoint());
// }

@Bean
public JwtAccessTokenAuthenticationFilter jwtAccessTokenAuthenticationFilter() throws Exception {
authenticationManagerBuilder.authenticationProvider(jwtAuthenticationProvider());
return new JwtAccessTokenAuthenticationFilter(authenticationManager(), jwtAuthenticationEntryPoint(), permitJwtUrlList);
}

@Bean
public JwtRefreshTokenAuthenticationFilter jwtRefreshTokenAuthenticationFilter() throws Exception {
return new JwtRefreshTokenAuthenticationFilter(authenticationManager(), jwtAuthenticationEntryPoint());
}

@Bean
public AuthenticationProvider jwtAuthenticationProvider() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ public class JwtAccessTokenAuthenticationFilter extends OncePerRequestFilter {

private final List<String> permitUrlList;

/**
* AccessToken, RefreshToken에 사용하는 Provider의 기능이 완전히 같아서 1개의 Provider만 사용
* Provider에서 발생한 예외가 AccessToken에서 발생한 예외인지, RefreshToken에서 발생한 예외인지 구분이 필요했습니다.
* 그래서 기존 메시지를 집어넣어 되던졌습니다.
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (isPermitted(request.getRequestURI())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package com.ogjg.daitgym.config.security.oauth.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ogjg.daitgym.common.exception.ErrorCode;
import com.ogjg.daitgym.common.response.ApiResponse;
import com.ogjg.daitgym.config.security.details.OAuth2JwtUserDetails;
import com.ogjg.daitgym.config.security.jwt.dto.JwtUserClaimsDto;
import com.ogjg.daitgym.config.security.oauth.dto.LoginResponseDto;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -49,13 +46,13 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo

String cachedUrl = getCachedUrlOrDefault(request, response);

objectMapper.writeValue(
response.getWriter(),
new ApiResponse<>(
ErrorCode.SUCCESS,
LoginResponseDto.of(OAuth2UserDetails, cachedUrl)
)
);
// objectMapper.writeValue(
// response.getWriter(),
// new ApiResponse<>(
// ErrorCode.SUCCESS,
// LoginResponseDto.of(OAuth2UserDetails, cachedUrl)
// )
// );
}

private void addTokensInHeader(HttpServletResponse response, JwtUserClaimsDto jwtUserClaimsDto) {
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/ogjg/daitgym/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,8 @@ public void changeHealthClub(HealthClub newHealthClub) {
}
this.healthClub = newHealthClub;
}
}

public boolean isAdmin() {
return this.role == Role.ADMIN;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.ogjg.daitgym.user.controller;

import com.ogjg.daitgym.common.exception.ErrorCode;
import com.ogjg.daitgym.common.response.ApiResponse;
import com.ogjg.daitgym.user.dto.LoginResponseDto;
import com.ogjg.daitgym.user.service.AuthService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class LoginController {

private final AuthService authService;

@GetMapping("/login/oauth2/callback/kakao")
public ApiResponse<LoginResponseDto> kakaoLogin(
@RequestParam("code") String code,
HttpServletResponse httpServletResponse
) {
String kakaoAccessToken = authService.getKakaoAccessToken(code).getAccess_token();

return new ApiResponse<>(
ErrorCode.SUCCESS,
authService.kakaoLogin(kakaoAccessToken, httpServletResponse)
);
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/ogjg/daitgym/user/dto/KakaoAccountDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.ogjg.daitgym.user.dto;

import lombok.Data;
import lombok.Getter;

@Getter
public class KakaoAccountDto {

private Long id;
private KakaoAccount kakao_account;
@Data
public static class KakaoAccount {

private String email;
private Profile profile;

@Data
public static class Profile {

private String nickname;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
package com.ogjg.daitgym.config.security.oauth.dto;
package com.ogjg.daitgym.user.dto;

import com.ogjg.daitgym.config.security.details.OAuth2JwtUserDetails;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.UUID;

@Getter
@Builder
@NoArgsConstructor
public class LoginResponseDto {
private String email;

private String nickname;

private String userImg;

private String initialRequestUrl;
private String preferredSplit;

private boolean isAlreadyJoined;

public LoginResponseDto(String email, String nickname, String userImg, String initialRequestUrl, boolean isAlreadyJoined) {
this.email = email;
private boolean isAdmin;

private boolean isDeleted;

@Builder
public LoginResponseDto(String nickname, String userImg, String preferredSplit, boolean isAlreadyJoined, boolean isAdmin, boolean isDeleted) {
this.nickname = nickname;
this.userImg = userImg;
this.initialRequestUrl = initialRequestUrl;
this.preferredSplit = preferredSplit;
this.isAlreadyJoined = isAlreadyJoined;
this.isAdmin = isAdmin;
this.isDeleted = isDeleted;
}

public static LoginResponseDto of(OAuth2JwtUserDetails oAuth2UserDetails, String initialRequestUrl) {
public static LoginResponseDto from(OAuth2JwtUserDetails oAuth2UserDetails) {
return LoginResponseDto.builder()
.nickname(oAuth2UserDetails.getNickname())
.email(oAuth2UserDetails.getEmail())
.nickname(UUID.randomUUID().toString())
.userImg("default")
.initialRequestUrl(initialRequestUrl)
.isAlreadyJoined(oAuth2UserDetails.isAlreadyJoined())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

import com.ogjg.daitgym.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User,String> {
Optional<User> findByNickname(String nickName);

Optional<User> findByEmail(String email);


@Query("""
select u from User u where u.email = :email
""")
Optional<User> findByEmailIncludingDeleted(@Param("email") String email);
}
Loading

0 comments on commit e875414

Please sign in to comment.