Spring Boot/Security

Spring Boot - spring security + oauth2

최-코드 2024. 4. 11. 23:23

각각의 필터가 동작하는 주소

OAuth2AuthorizationRequestRedirectFilter : /oauth2/authorization/서비스명

OAuth2LoginAuthenticationFilter : /login/oauth2/code/서비스명 ( redirect_uri이다. )
이 때 서비스명은 카카오면 kakao와 같이 registrationId를 적어주면 된다.

 

기본적인 로직은 /oauth2/authorization/서비스명으로 요청이 들어오면 서비스명 즉, registrationId에 해당하는 설정 파일을 참고하여 authorization-uri을 통해 로그인 페이지로 이동한다. 이후 로그인이 성공하면 redirect_uri 경로로 리다이렉트하는데, 이 때 code를 붙여서 리다이렉트를 진행한다.

 

 

properties 설정만 하면 OAuth2AuthorizationRequestRedirectFilter, OAuth2LoginAuthenticationFilter, OAuth2LoginAuthenticationProvider까지는 자동으로 이뤄진다. 따라서 UserDetailsService와 UserDetails만 구현하면 된다.

 

properties

spring.security.oauth2.client.registration.kakao.client-name=kakao
spring.security.oauth2.client.registration.kakao.client-id=앱키 입력
spring.security.oauth2.client.registration.kakao.client-secret=보안에 client secret 입력
spring.security.oauth2.client.registration.kakao.redirect-uri=https://localhost:8080/login/oauth2/code/kakao
spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code #임의 설정 X 정해진 방식이 있음
spring.security.oauth2.client.registration.kakao.client-authentication-method=client_secret_post #not POST

spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
spring.security.oauth2.client.provider.kakao.user-name-attribute=id

 

SecurityConfig.java

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final CustomOAuth2UserService customOAuth2UserService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable);
        http
                .formLogin(AbstractHttpConfigurer::disable);
        http
                .httpBasic(AbstractHttpConfigurer::disable);
        http    //oauth2Login()은 oauth2 관련 필터 사용하게 하는 역할
                .oauth2Login((oauth2)->oauth2
                        //리소스 서버에서 정보를 가져왔을 때 실행할 UserService 설정
                        .userInfoEndpoint((userInfoEndpoint)->userInfoEndpoint
                                .userService(customOAuth2UserService))
                        //.defaultSuccessUrl("/success"); 로그인 성공시 이동할 url 설정
        http
                .authorizeHttpRequests((auth)->auth
                        .requestMatchers("/","/oauth2/**","/login/**").permitAll()
                        .anyRequest().authenticated());
        return http.build();
    }
}

 

CustomOAuth2User.java

//                  UserDetails와 유사
public class CustomOAuth2User implements OAuth2User {

    private final OAuth2Response oAuth2Response;
    private final String role;

    public CustomOAuth2User(OAuth2Response oAuth2Response, String role) {
        this.oAuth2Response = oAuth2Response;
        this.role = role;
    }
    @Override
    public Map<String, Object> getAttributes() {
        return null;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(role));
        return authorities;
    }

    @Override
    public String getName() {
        return oAuth2Response.getnickname();
    }
}

 

CustomOAuth2UserService.java

@Service
@RequiredArgsConstructor
//                          UserDetailsService와 유사
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
    private final UserRepository userRepository;

    @Override
    //                              OAuth2UserRequest에는 access token과 설정 정보가 포함되어 있다.
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        //                          user 가져오기
        OAuth2User oAuth2User = super.loadUser(userRequest);
        //                            getAttributes()에는 리소스 서버에서 보낸 유저 정보가 있다.
        System.out.println(oAuth2User.getAttributes());

//        userRequest.getClientRegistration().getRegistrationId()로
//        서비스명 받아온 뒤에 서비스에 맞는 Response 생성
        OAuth2Response oAuth2Response = new KakaoResponse(oAuth2User.getAttributes());

        String role = "ROLE_USER";

        Optional<UserEntity> byRegistrationId = userRepository
                .findByRegistrationId(oAuth2Response.getId());

        if (byRegistrationId.isPresent()) {
            UserEntity user = byRegistrationId.get();
            user.setNickname(oAuth2Response.getnickname());
        } else {
            UserEntity user = new UserEntity();
            user.setNickname(oAuth2Response.getnickname());
            user.setRegistrationId(oAuth2Response.getId());
            user.setRole(role);
            userRepository.save(user);
        }
        //UserDetailsService와 다른 점은 이 때 리턴한 것은 그저 SecurityContextHolder에 저장하기 위함
        return new CustomOAuth2User(oAuth2Response, role);
    }
}