저는 개발자는 아니지만 회사 내부 검토 목적으로 문의드립니다. 현재 저희 회사에서 , 소셜 로그인(구글, 카카오, 네이버, 애플) API 신청 시 어떤 서류가 필요한지 파악이 필요한 상황입니다. 구체적으로 아래 내용이 궁금합니다: 1. 소셜 로그인 API 사용 신청 시 제출해야 하는 서류가 어떤 것들이 있나요? 2. 사업자등록증 등 법인 관련 서류가 반드시 필요한가요? 3. 개인 개발자와 법인(회사) 기준으로 신청 절차나 필요 서류가 다른가요? 비개발자 입장에서 드리는 질문이라 다소 기초적일 수 있지만, 내부 검토에 필요한 내용이라 문의하게 되었습니다. AI를 통해 답변을 받았으나 참고용으로만 생각하고, 정확한 내용을 확인하고자 문의드립니다. - AI 답변 : 각 플랫폼별로 회원가입 진행 후, 별도 서류 없이 API 발급 가능
카카오연동 첫강의 부터 막히기 시작합니다ㅠ 카카오 연동설정 UI도 일단 많이 변경되었고 리다이렉트 URI란 항목이 웹훅으로 변경된거 같은데 그곳에다 리다이렉트 주소를 입력하면 https프로토콜만 이제 등록되는거 같습니다. 이부분은 새롭게 다른 방면으로 소셜로그인 업데이트 해야될꺼 같아 보여요ㅠ
스프링부트 REST + OAuth2 + JWT를 사용하고 있는 상황인데 로컬에서는 잘 돌아갑니다. 로컬에서 소셜로그인이 성공하면 OAuth2SuccessHandler에서 바로 JSON으로 반환해주는 형태입니다. 즉, 컨트롤러가 딱히 무슨 역할을 하지 않아도 바로 반환을 해줍니다. 하지만 EC2에 배포하고 구글 개발자 센터, yml에 EC2 퍼블릭을 제대로 입력해주고 제대로 일치하는 것을 확인했고 버튼을 클릭하면 아이디들이 제대로 뜹니다. 하지만 로그인한 결과 로그인할 아이디를 클릭을 하면 Whitelabel Error Page 404페이지가 뜹니다. 그래서 실패했을 때 JSON으로 반환시켜주는 로직을 추가해서 확인한 결과 "error 발생 : ": "[authorization_request_not_found] " 이러한 오류가 발생했습니다. 항상 체크해야하는요소 yml 체크함 구글 개발자 센터 확인함 → 1, 2번은 일치함 EC2 인스턴스의 보안 그룹이 OAuth2 콜백 URL로 요청을 수신할 수 있도록 올바르게 설정되었는지 확인 → 이거는 어떻게 다른 설정법이 있을까요? application.yml 또는 application.properties 에 설정된 값들이 프로덕션 환경에 맞게 정확히 설정 이렇게 환경변수를 받아서 ec2 배포시 사용할 수 있도록 설정했는데 추가적으로 또 뭔가를 해줘야 하나요? 혹시 OAuth2 google을 테스터로 해놓고 http로 해놓으면 ec2 배포시에는 사용하지 못하나요?
security에서 OAuth2 클라이언트를 사용해서 구글이나 네이버 api를 사용하지 않고 자동으로 소셜 로그인 accessToken을 검증해주고 정보를 가져올 수 있다는 기능이 있는걸로 알고있어서 gpt에 검색해보니 package com.example.social.config.security; import com.example.social.config.jwt.JwtAccessDeniedHandler; import com.example.social.config.jwt.JwtAuthenticationEntryPoint; import com.example.social.config.jwt.JwtProvider; import com.example.social.config.oauth2.PrincipalOauth2UserService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.DelegatingPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.SecurityFilterChain; import java.util.HashMap; import java.util.Map; @Configuration @RequiredArgsConstructor @EnableWebSecurity public class SecurityConfig { private final PrincipalOauth2UserService principalOauth2UserService; private final JwtProvider jwtProvider; @Value("${spring.security.oauth2.client.registration.google.client-id}") private String googleClientId; @Value("${spring.security.oauth2.client.registration.google.client-secret}") private String googleClientSecret; @Value("${spring.security.oauth2.client.registration.naver.client-id}") private String naverClientId; @Value("${spring.security.oauth2.client.registration.naver.client-secret}") private String naverClientSecret; @Bean // InMemoryClientRegistrationRepository를 생성하고 반환합니다. // InMemoryClientRegistrationRepository는 OAuth 2.0 클라이언트 등록 정보를 // 메모리에 보관하고 관리하는 데 사용됩니다. public InMemoryClientRegistrationRepository clientRegistrationRepository() { // ClientRegistration 객체를 생성하고 OAuth 2.0 클라이언트의 등록 정보를 설정합니다. ClientRegistration googleRegistration = ClientRegistration .withRegistrationId("google") .clientId(googleClientId) .clientSecret(naverClientSecret) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri("http://localhost:8080/login/oauth2/code/google") // Google의 authorizationUri .authorizationUri("https://accounts.google.com/o/oauth2/auth") .tokenUri("https://oauth2.googleapis.com/token") .scope("openid", "profile", "email") .clientName("Google") .build(); ClientRegistration naverRegistration = ClientRegistration .withRegistrationId("naver") .clientId(naverClientId) .clientSecret(naverClientSecret) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri("http://localhost:8080/login/oauth2/code/naver") // Naver의 authorizationUri .authorizationUri("https://nid.naver.com/oauth2.0/authorize") .tokenUri("https://nid.naver.com/oauth2.0/token") .scope("openid", "profile", "email") .clientName("Naver") .build(); return new InMemoryClientRegistrationRepository(googleRegistration, naverRegistration); } @Bean // OAuth2UserService 타입의 빈을 생성합니다. 이 빈은 OAuth2 로그인 처리에 사용됩니다. // OAuth2UserService는 OAuth2 로그인 후에 사용자 정보를 가져오고 처리하는 인터페이스입니다. public OAuth2UserService<OAuth2UserRequest, OAuth2User> googleOAuth2UserOAuth2UserService() { // new DefaultOAuth2UserService() { ... }: // OAuth2UserService 인터페이스를 구현하는 익명 클래스를 생성합니다. // 이 클래스는 OAuth2 로그인 처리에 사용될 사용자 서비스를 정의합니다. return new DefaultOAuth2UserService() { @Override // loadUser(OAuth2UserRequest userRequest) { ... }: // OAuth2UserService 인터페이스의 loadUser 메서드를 오버라이드합니다. // 이 메서드는 OAuth2 로그인 후에 호출되며, 사용자 정보를 가져옵니다. public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // super.loadUser(userRequest)를 호출하여 OAuth2 로그인 후에 사용자 정보를 가져옵니다. // OAuth2User 객체는 사용자의 인증된 속성 및 권한을 포함하고 있습니다. OAuth2User user = super.loadUser(userRequest); // OAuth2 로그인 후에 반환되는 OAuth2User 객체를 수정하거나 구성하여 반환합니다. // 여기에서는 사용자의 권한, 속성 및 고유 식별자(sub)를 포함하는 // DefaultOAuth2User 객체를 반환하고 있습니다. return new DefaultOAuth2User( user.getAuthorities(), user.getAttributes(), // 사용자의 고유 식별자 (일반적으로 'sub'라는 속성에 저장됨) "sub" ); } }; } // naver @Bean @Qualifier("naver") public OAuth2UserService<OAuth2UserRequest, OAuth2User> naverOAuth2UserService() { return new DefaultOAuth2UserService() { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2User user = super.loadUser(userRequest); // 사용자 정보 처리 // user.getName(), user.getAttributes()를 사용하여 필요한 정보를 가져올 수 있음 String uniqueIdentifier = user.getAttribute("id"); return new DefaultOAuth2User( user.getAuthorities(), user.getAttributes(), uniqueIdentifier ); } }; } @Bean public SecurityFilterChain filterChain( HttpSecurity http) throws Exception { http // HTTP 기본 인증 비활성화 .httpBasic().disable() // CSRF(Cross-Site Request Forgery) 공격 방어 비활성화 .csrf().disable() // 폼 기반 로그인 비활성화 .formLogin().disable() // 로그아웃 관련 설정 비활성화 .logout().disable() // 세션 관리를 STATELESS로 설정하여 세션을 사용하지 않도록 설정 // JWT를 사용할거기 때문 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http .authorizeRequests() .antMatchers("/api/v1/users/**").permitAll(); http // JWT를 위한 Filter를 아래에서 만들어 줄건데 // 이 Filter를 어느위치에서 사용하겠다고 등록을 해주어야 Filter가 작동이 됩니다. // JWT를 검증하기 위한 JwtSecurityConfig를 적용하고 // jwtProvider를 사용하여 JWT 검증을 수행합니다. .apply(new JwtSecurityConfig(jwtProvider)); // 에러 방지 http .exceptionHandling() // 인증 에러 핸들링을 위한 커스텀 JwtAuthenticationEntryPoint 등록. .authenticationEntryPoint(new JwtAuthenticationEntryPoint()) // 권한 에러 핸들링을 위한 커스텀 JwtAccessDeniedHandler 등록 .accessDeniedHandler(new JwtAccessDeniedHandler()); // OAuth2 http // oauth2Login() 메서드는 OAuth 2.0 프로토콜을 사용하여 소셜 로그인을 처리하는 기능을 제공합니다. .oauth2Login() .clientRegistrationRepository(clientRegistrationRepository()) // OAuth2 로그인 성공 이후 사용자 정보를 가져올 때 설정 담당 .userInfoEndpoint() // OAuth2 로그인 성공 시, 후작업을 진행할 서비스 .userService(principalOauth2UserService); // http // // Spring Security에게 OAuth2 리소스 서버를 설정하도록 지시하는 부분입니다. // // 즉, 이 설정 아래에서 JWT를 검증하는 데 필요한 구성을 수행합니다. // .oauth2ResourceServer() // // OAuth2 리소스 서버가 JWT 토큰을 사용한다고 알려줍니다. // // Spring Security에 JWT 검증을 수행하도록 설정합니다. // .jwt() // // JWT 디코더를 설정합니다. // // JWT 디코더는 JWT 토큰을 검증하고 내용을 추출하는 데 사용됩니다. // .decoder(this.jwtDecoder()); return http.build(); } @Bean PasswordEncoder passwordEncoder() { String idForEncode = "bcrypt"; Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put(idForEncode, new BCryptPasswordEncoder()); return new DelegatingPasswordEncoder(idForEncode, encoders); } // JWT 디코더를 생성하는 메서드를 정의합니다. // Google의 공개 키를 가져와 JWT 토큰의 서명을 검증하기 위해 사용합니다. // withJwkSetUri 메서드를 통해 Google의 공개 키를 가져오는 URI를 지정합니다. // 이러한 구성을 통해 Spring Security는 Google OAuth2에서 제공하는 JWT 토큰의 유효성을 검사하고, // 토큰이 유효하면 해당 사용자에 대한 정보를 추출할 수 있습니다. // @Bean // public JwtDecoder jwtDecoder() { // return NimbusJwtDecoder.withJwkSetUri("https://www.googleapis.com/oauth2/v3/certs") // .build(); // } } 이런식으로 나오더군요. 생각하는 로직은 프론트에서 소셜로그인이 성공하면 accessToken을 받고 그거를 바로 서버에 보내줘서 헤더에 담긴 accessToken을 security 기능으로 검증하고 정보를 빼오려고 했습니다. 일반로그인시 제가 만든 JWT를 반환해서 accessToken을 JwtAuthenicationFilter에서 검증한다면 소셜 로그인 accessToken은 security가 지원하는 기능으로 검증하려고 했는데 제가 잘못생각하고 있는건지 소셜 로그인 accessToken이 계속 JwtAuthenicationFilter에서 검사하고 틀린 JWT라고 나오네요. git : https://github.com/YuYoHan/social_login 질문 1: 제가 생각하고 있는 흐름이 맞나요? 질문 2: 1번이 맞다면 security 기능으로 사용해서 어떻게 소셜 로그인 accessToken을 검사할 수 있나요? 질문 3: 1번이 틀렸다면 어느 부분이 틀리고 어떻게 수정해야할까요? 현재 JWT 발급과 JWT를 검증하는 부분은 성공했지만 소셜 로그인 accessToken을 검증해서 정보를 빼와서 JWT를 만들어 반환해주는 부분이 막혀있는 상태입니다 ㅠㅠ 도와주세요
현재 상황 클라이언트와 서버를 각자 다른 도메인에 배포했습니다. 소셜 로그인은 passport 모듈과 session을 사용했습니다. 서버에서 소셜 로그인이 성공해도 클라이언트에는 세션 쿠키가 전달되지 않습니다. 클라이언트 axios get 요청을 보내면 cors 에러가 떠서 a 태그를 사용했습니다. <a href="http://서버ip/auth/github">깃 헙 로그인<a/> 서버 아래의 코드는 강의의 내용과 동일합니다. passport 모듈을 활용해 소셜 로그인을 구현했습니다. import express from "express"; import passport from "passport"; import { isLoggedIn, isNotLoggedIn } from "../middlewares/authMiddleware.js"; const router = express.Router(); router.get("/github", passport.authenticate("github")); router.get( "/github/callback", passport.authenticate("github", { failureRedirect: "/", }), (req, res) => { res.redirect(`http://localhost:3000`); } ); router.get("/logout", isLoggedIn, (req, res) => { req.logout(); req.session.destroy(); res.json({ message: "logout" }); }); export default router; 소셜 로그인에 성공하면 클라이언트 서버의 메인 페이지로 redirect 시키고 있습니다. 문의 서버에서 소셜 로그인 성공시 클라이언트 서버에도 session 쿠키를 전달하고 싶습니다. 두 개의 다른 서버에서 소셜 로그인을 어떻게 구현해야될지 모르겠습니다.
강사님 덕분이 장고 공부 잘 하고 있습니다. 장고 소셜 로그인 할 때 저는 다음 창이 나오네요? 강사님은 로그인할 때 안나오던데요. 로그인, 로그아웃 할 때도 안나오게 하고싶은데 방법이 있을까요? 로그인 버튼 눌렀을 때 나오는 첫화면 로그아웃 버튼 눌렀을 때 나오는 화면 관련 문의는 1:1 문의하기를 이용해주세요.