묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결
엑셀버전 호환 관련(파워쿼리)
안녕하세요.최근 배영자님의 파워쿼리 들었는데신세계더라구요 그런데 저희회사는 2013 프로페셔널 사용중이라제껄 2016으로 바꿔달라고 요청예정인데요--질문--"제가 2016에서 가공한 엑셀파일을2013프로페셔널 사용중인 다른 동료들이제한없이 쓸수있나요?" 감사합니다
-
해결됨[퇴근후딴짓] 빅데이터 분석기사 실기 (작업형1,2,3)
데이터 합치고 분리하는 경우 질문입니다!
영상에는 원핫 인코딩만 데이터 수가 안맞는 경우 데이터를 합치고 분리하는 실습을 보여주셨습니다.라벨 인코딩의 경우도 데이터 수가 안맞는 경우 합쳤다가 라벨 인코딩 진행후 분리시키면 되는건가요?
-
해결됨김영한의 실전 자바 - 기본편
객체(데이터성, 기능성) 관련해서 질문이 있습니다.
안녕하세요. 강사님!OOP 관련 강의나 책들을 보다가 설명하는 방식이 다 달라서 오히려 머릿속이 더 복잡해진거 같아서 질문드리게 되었습니다.여러 강의 또는 책에서 예를 들어 책임 주도 설계와 같은 곳에서는 객체는 외부에 제공하는 기능으로서 평가되어진다.그래서 객체는 외부에 제공하는 기능이 있고 그 기능 구현에 필요한 데이터를 가진다. 따라서 기능 기반으로 해서 각 객체를 디자인해야 된다! 이런식으로 이해를 하고 있었습니다.그런데 직접 설계를 진행하면 할 수록 결국 데이터 성격이 강한 구조체성 객체를 디자인해야 되더라구요! 기능 보다 데이터를 우선적으로 추출하는 방식으로요!또 추가적으로 영한님의 스프링 강의를 보면 오히려 데이터베이스 테이블 설계(Entity) 이후에 각 기능들을 적절히 도메인 모델(Entity)에 분배하는 형식으로 디자인을 하시더라구요. 저같은 경우 웹 개발을 진행할 때는 뭔가 정보를 표현해야 될 것들이 있다보니 테이블 설계를 우선시하고 기능 구현에 필요한 정보를 많이 알고있는 곳에 분배하는 식으로 하려고 노력하고 있긴한대 잘안되지만요...데이터를 우선 추출하고 거기에 별도의 기능을 추가하는 방식도 적절한 객체 설계 방식이라고 볼 수 있을까요?기능을 수행할 객체를 정하고 기능 구현에 필요한 데이터를 객체에 추가하는 방식과 데이터베이스 테이블 설계 이후에 정보 전문가 패턴을 따라서 각 기능을 분배하는 방식중에 어떤게 맞는건지 해당 2개의 개념은 다른 것을 설명하는 것인지 조언을 좀 부탁드리겠습니다!감사합니다.
-
미해결
배포후 소셜로그인 에러
스프링부트 REST + OAuth2 + JWT를 사용하고 있는 상황인데로컬에서는 잘 돌아갑니다.로컬:<a id="google-login" href="/oauth2/authorization/google">구글 로그인</a> <a id="naver-login" href="/oauth2/authorization/naver">네이버 로그인</a> @Service @Log4j2 @RequiredArgsConstructor public class PrincipalOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { private final MemberRepository memberRepository; private final JwtProvider jwtProvider; private final TokenRepository tokenRepository; @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // userRequest.getClientRegistration()은 인증 및 인가된 사용자 정보를 가져오는 // Spring Security에서 제공하는 메서드입니다. ClientRegistration clientRegistration = userRequest.getClientRegistration(); log.info("clientRegistration : " + clientRegistration); // 소셜 로그인 accessToken String socialAccessToken = userRequest.getAccessToken().getTokenValue(); log.info("소셜 로그인 accessToken : " + socialAccessToken); OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService = new DefaultOAuth2UserService(); log.info("oAuth2UserService : " + oAuth2UserService); // 소셜 로그인한 유저정보를 가져온다. OAuth2User oAuth2User = oAuth2UserService.loadUser(userRequest); log.info("oAuth2User : " + oAuth2User); log.info("getAttribute : " + oAuth2User.getAttributes()); // 회원가입 강제 진행 OAuth2UserInfo oAuth2UserInfo = null; String registrationId = clientRegistration.getRegistrationId(); log.info("registrationId : " + registrationId); if(registrationId.equals("google")) { log.info("구글 로그인"); oAuth2UserInfo = new GoogleUser(oAuth2User, clientRegistration); } else if(registrationId.equals("naver")) { log.info("네이버 로그인"); oAuth2UserInfo = new NaverUser(oAuth2User, clientRegistration); } else { log.error("지원하지 않는 소셜 로그인입니다."); } // 사용자가 로그인한 소셜 서비스를 가지고 옵니다. // 예시) google or naver 같은 값을 가질 수 있다. String provider = oAuth2UserInfo.getProvider(); // 사용자의 소셜 서비스(provider)에서 발급된 고유한 식별자를 가져옵니다. // 이 값은 해당 소셜 서비스에서 유니크한 사용자를 식별하는 용도로 사용됩니다. String providerId = oAuth2UserInfo.getProviderId(); String name = oAuth2UserInfo.getName(); // 사용자의 이메일 주소를 가지고 옵니다. // 소셜 서비스에서 제공하는 이메일 정보를 사용합니다. String email = oAuth2UserInfo.getEmail(); // 소셜 로그인의 경우 무조건 USER 등급으로 고정이다. Role role = Role.USER; MemberEntity findUser = memberRepository.findByEmail(email); if(findUser == null) { log.info("소셜 로그인이 최초입니다."); log.info("소셜 로그인 자동 회원가입을 진행합니다."); findUser = MemberEntity.builder() .email(email) .memberName(name) .provider(provider) .providerId(providerId) .memberRole(role) .nickName(name) .build(); log.info("member : " + findUser); findUser = memberRepository.save(findUser); } else { log.info("로그인을 이미 한적이 있습니다."); } // 권한 가져오기 List<GrantedAuthority> authorities = getAuthoritiesForUser(findUser); // 토큰 생성 TokenDTO tokenForOAuth2 = jwtProvider.createTokenForOAuth2(email, authorities, findUser.getMemberId()); // 기존에 이 토큰이 있는지 확인 TokenEntity findToken = tokenRepository.findByMemberEmail(tokenForOAuth2.getMemberEmail()); TokenEntity saveToken; // 기존의 토큰이 없다면 새로 만들어준다. if(findToken == null) { TokenEntity tokenEntity = TokenEntity.tokenEntity(tokenForOAuth2); saveToken = tokenRepository.save(tokenEntity); log.info("token : " + saveToken); } else { // 기존의 토큰이 있다면 업데이트 해준다. tokenForOAuth2 = TokenDTO.builder() .grantType(tokenForOAuth2.getGrantType()) .accessToken(tokenForOAuth2.getAccessToken()) .accessTokenTime(tokenForOAuth2.getAccessTokenTime()) .refreshToken(tokenForOAuth2.getRefreshToken()) .refreshTokenTime(tokenForOAuth2.getRefreshTokenTime()) .memberEmail(tokenForOAuth2.getMemberEmail()) .memberId(tokenForOAuth2.getMemberId()) .build(); TokenEntity tokenEntity = TokenEntity.updateToken(findToken.getId(), tokenForOAuth2); saveToken = tokenRepository.save(tokenEntity); log.info("token : " + saveToken); } // 토큰이 제대로 되어 있나 검증 if(StringUtils.hasText(saveToken.getAccessToken()) && jwtProvider.validateToken(saveToken.getAccessToken())) { Authentication authenticationToken = jwtProvider.getAuthentication(saveToken.getAccessToken()); log.info("authentication : " + authenticationToken); SecurityContextHolder.getContext().setAuthentication(authenticationToken); UserDetails userDetails = new User(email, "", authorities); log.info("userDetails : " + userDetails); Authentication authenticationUser = new UsernamePasswordAuthenticationToken(userDetails, authorities); log.info("authentication1 : " + authenticationUser); SecurityContextHolder.getContext().setAuthentication(authenticationUser); } else { log.info("검증 실패"); } // attributes가 있는 생성자를 사용하여 PrincipalDetails 객체 생성 // 소셜 로그인인 경우에는 attributes도 함께 가지고 있는 PrincipalDetails 객체를 생성하게 됩니다. PrincipalDetails principalDetails = new PrincipalDetails(findUser, oAuth2User.getAttributes()); log.info("principalDetails : " + principalDetails); return principalDetails; } // 권한 가져오기 로직 private List<GrantedAuthority> getAuthoritiesForUser(MemberEntity findUser) { Role role = findUser.getMemberRole(); List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("ROLE_" + role.name())); log.info("권한 : " + role.name()); return authorities; } } @Log4j2 @RequiredArgsConstructor @Component public class OAuth2SuccessHandler implements AuthenticationSuccessHandler { private final MemberRepository memberRepository; private final TokenRepository tokenRepository; // Jackson ObjectMapper를 주입합니다. private final ObjectMapper objectMapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { try { log.info("OAuth2 Login 성공!"); // 소셜 로그인 이메일 가져오기 String email = authentication.getName(); log.info("email : " + email); // 토큰 조회 TokenEntity findToken = tokenRepository.findByMemberEmail(email); log.info("token : " + findToken); // 토큰 DTO 반환 TokenDTO tokenDTO = TokenDTO.toTokenDTO(findToken); // 회원 조회 MemberEntity findUser = memberRepository.findByEmail(email); // 회원 DTO 반환 ResponseMemberDTO memberDTO = ResponseMemberDTO.socialMember(findUser); // 헤더에 담아준다. response.addHeader("email", memberDTO.getEmail()); // 바디에 담아준다. Map<String, Object> responseBody = new HashMap<>(); responseBody.put("providerId", memberDTO.getProviderId()); responseBody.put("provider", memberDTO.getProvider()); responseBody.put("accessToken", tokenDTO.getAccessToken()); responseBody.put("refreshToken", tokenDTO.getRefreshToken()); responseBody.put("email", tokenDTO.getMemberEmail()); responseBody.put("memberId", tokenDTO.getMemberId()); responseBody.put("grantType", tokenDTO.getGrantType()); // JSON 응답 전송 response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(responseBody)); } catch (Exception e) { // 예외가 발생하면 클라이언트에게 오류 응답을 반환 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write("OAuth 2.0 로그인 성공 후 오류 발생: " + e.getMessage()); response.getWriter().flush(); } } }로컬에서 소셜로그인이 성공하면 OAuth2SuccessHandler에서 바로 JSON으로 반환해주는 형태입니다. 즉, 컨트롤러가 딱히 무슨 역할을 하지 않아도 바로 반환을 해줍니다. 하지만 EC2에 배포하고 구글 개발자 센터, yml에 EC2 퍼블릭을 제대로 입력해주고로그인한 결과 아이디들 제대로 뜨는데 로그인할 아이디를 클릭을 하면Whitelabel Error Page 404페이지가 뜹니다. 로컬 코드를 그대로 배포한건데 왜 안될까요?
-
미해결
MemberService에는 왜 MemberRepository를 주입하지 않는 건가요??
@Transactional public class MemberService { MemberRepository memberRepository; public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } public Optional<Member> findOne(long id){ return memberRepository.findById(id); } public long save(Member member){ valiateDuplicateMember(member); // 중복회원 검증 memberRepository.save(member); return member.getId(); } private void valiateDuplicateMember(Member member) { memberRepository.findByName(member.getName()).ifPresent( // findByName이 Optional을 리턴하니까 null이 아니면 중복 검사를 실행 m -> { throw new IllegalStateException("이미 존재하는 회원입니다."); } ); } public List<Member> findAll(){ return memberRepository.findAll(); } public void deleteOne(Member member){ memberRepository.deleteAllInBatch(member); } } 여기서 MemberService는 여러가지 연산을 하기 위해서 memberRepository가 필요한데 의존성 주입을 하지 않는 이유가 있는지 궁금합니다!
-
미해결스프링 핵심 원리 - 기본편
Process finished with exit code 0
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. Process finished with exit code 0 이 문장 안 나와도 상관 없나요? 감사합니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
특정 위치에서 player가 Monster의 바로 옆을 click하면 버그가 발생합니다.
player가 현 위치에서 해당 지점을 이동하고자 클릭하면(마우스는 Monster가 아닌 Ground를 가리켜서 cursor icon은 HandIcon상태) 캐릭터가 monster앞에서 movespeed가 느려지고 해당 지점(Ground)으로 가는게 아니라 몬스터의 position에 가면서도 monster를 공격하는게 아닌, 몬스터에게 이동만 하는 상태가 나타나는 버그가 발생합니다. (공격을 하지 않고 이동만 하는 모습) 이를 해결해보고자 여러차례 시도해보다가 결국 실패해서 질문으로 남깁니다. -공격#2
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
CreateProcess error=5, 액세스가 거부되었습니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요,프로젝트 오픈하고 처음에 run 돌릴 때 아래와 같은 에러가 발생합니다.(강의 6:06초) CreateProcess error=5, 액세스가 거부되었습니다 Execution failed for task ':ServletApplication.main()'.> A problem occurred starting process 'command 'C:\Program Files\Java\jdk-17\bin\java.exe'' 인터넷에 찾아보니 C드라이브에 접근하는 권한 문제일 수 있다고 하는데 해결책은 따로 나와 있지 않아 문의드립니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
new를 이용하지 않는 이유
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. 궁금한 점이 생겨 질문 드립니다.1.3분 4초 즈음 new로 인스턴스를 생성해서 사용하면 MemberSerivce를 MemberController 말고 다른 컨트롤러도 가져다 쓸 수 있다고 언급하셨는데 private인데도 접근할 수 있는 건가요,,,? 실행버튼이 나오지 않아 커뮤니티 검색해서 helloSpringApplication에서 작동시켜서 선생님과 같은 화면까지는 나왔는데요, 선생님께서는 컨트롤러에도 실행 버튼이 있는데 제 거에는 없는 이유가 있을까요..? 무료와 유료의 차이인가요?감사합니다!
-
해결됨[퇴근후딴짓] 빅데이터 분석기사 실기 (작업형1,2,3)
test에서 결측치가 발생할 경우
학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!질문과 관련된 영상 위치를 알려주면 더 빠르게 답변할 수 있어요먼저 유사한 질문이 있었는지 검색해보세요질문 : test에서 결측치가 발생할 경우엔 행을 삭제 못하나요? test 파일의 경우 저희가 시험장에서 볼 수 있는 것은 X_test 파일이고, y_test는 저희가 볼 수 없는 파일이잖아요. 그럼 X_test의 행을 삭제하면 오류가 뜨나요? 예를 들어 X_test에서 행이 50개인데 행을 3개 삭제하면, y_test는 50개이니까 평가가 불가능하지 않을까 싶습니다. 즉, test에는 결측치가 발생하면 X_test.fillna()를 통해 대체를 할 수 있지, X_test.dropna()처럼 행을 삭제할 수 없나요? 강의 때 올려주신 예시문제나 기출문제 해설을 봐도 작업형2에는 모두 결측치가 없어서, 이렇게 질문으로 올립니다. 시험이 다가오니 사소해 보이는 질문도 확인을 받고 싶네요 ㅠㅠ 항상 감사합니다
-
미해결
강의 자료 찾기가 너무 불편하네요. "처음하는 SQL과 데이터베이스(MySQL) 부트캠프 [입문부터 활용까지]" 강의와 같이 하나로 묶어서 압축파일로 제공해주세요.
강의 자료를 어디서 다운 받나요. sqL 강의는 한 곳에서 다운 받을 수 있던데. 이 강의는 섹션별로 강의 자료를 나눠놓으셨가고 하는 데, 도저히 강의 자료를 찾을 수가 없네요. 한곳에서 다운 받을 수 있도록 짚파일로 압축해놓으면 강의에 참고가 되어 좋을 것 같습니다
-
해결됨[퇴근후딴짓] 빅데이터 분석기사 실기 (작업형1,2,3)
기출 6회 작업형2 질문입니다
모델들을 예측하고(랜덤 포레스트, 라이트bgm 등..) 둘 중에 랜덤 포레스트로 하겠다 라고 결정하면 라이트bgm 부분을 주석터리하면 자동적으로 pred가 랜덤포레스트 값으로 들어가는걸까요..?
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
new-form 404에러
[질문 내용]안녕하세요~강의 10분까지 따라했는데, 404에러가 떠서 문의드립니다. 전체 소스코드 : https://drive.google.com/file/d/1qj3jxUOuySgLPXIIgDvfKm38HXCpvLKD/view?usp=sharing
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Unreal과 연동
안녕하세요. 감사하게도, 좋은 서버 강의 잘들었습니다.끝으로 교육해주신 서버소스를Unreal엔진에 연동하기위해서 참고할 자료나 가이드가 있을지 여쭙고자 질문 남겨드립니다.확인 한번 부탁드리겠습니다. 감사합니다. 김준한 드림.
-
해결됨게임처럼 공부하는 git 던전
궁금증
강의에서 브랜치를 생성하자마자 그 브랜치에 대한 로컬 저장소가 따로 만들어지는 건지?그게 아니라면 로컬 저장소에서 저장하자마자 다른 브랜치로 작업한 내용이 전부 기존에로컬 저장소로 저장된 master랑 같아지는 상태가 아닌지?? 궁금합니다!!!!
-
해결됨게임처럼 공부하는 git 던전
브랜치를 만들었는데, 강의에서 stash할때 hotfix 브랜치 생성할때 질문
브랜치를 만들었는데, 강의에서 stash할때 hotfix 브랜치 생성할때 hotfix브랜치에 대한 local 저장소가 따로 만들어 지는걸까요? 하나의 로컬저장소에서 수정하는 것처럼 느껴져서 따라하다가 뭔가 이전 상태가 아닌것 같아서요 ㅠㅠ 다른 gui를 사용해서 그런지 헷깔려서 질문드립니다!
-
해결됨[퇴근후딴짓] 빅데이터 분석기사 실기 (작업형1,2,3)
작업형2에서 object 처리에 관련하여
작업형 2를 공부하던 중 분류, 회귀 상관없이 어떤 문제에선 object를 아예 drop 한 채로 문제를 풀거나, 어떤 문제에선 object를 원핫인코딩을 하던데 이런 기준이 따로 있나요,,,? 아예 drop 하지 않고 원핫인코딩 하는 것은 안 되나요?
-
미해결
웹 소켓 중 StompJS 사용 시 DB 저장이 안됩니다ㅠㅠ
안녕하세요 현재 웹 소켓 중 StompJS를 사용해서 채팅 기능을 구현 중이고 저는 프론트엔드(리액트)를 담당하고 있습니다. 현재 publish 메서드를 두 번 사용하는데 1번은 db에 저장하기 위해, 나머지 1번은 실시간 전송을 위해 사용합니다. 그런데 메시지를 실시간으로 주고 받는 건 되는데 DB에 저장이 안되는 상황입니다.. 그리고 이 코드가 완전히 안되는 건 아니라고 생각이 드는건 전날만 해도 DB 저장과 실시간 대화가 다 되었었다는 것입니다.. 제가 혹시 뭔가 잘못 건드린 부분이 있다거나 문제가 되는 부분을 알 수 있을까 해서 올려봅니다.. 물론 서버나 DB의 문제가 있을 수도 있다고 생각하지만 웹 소켓이 완전 처음이라서 이런 사용 방식이 맞는지도 궁금합니다..! 추가로 StompJs.Client의 debug로는 두 요청이 다 보내지는 로그가 뜨긴 하는 것 같아서 사진 첨부합니다! // 메세지 보내기 버튼 클릭 시 const sendMessageButtonClick = async () => { if (message.length > 0) { console.log('message', message); setHasInputError(false); // 메시지 보내기 // 이미 연결된 WebSocket이 있다면 메시지 전송 if (webSocketClient && webSocketClient.connected) { // 특정 채팅방으로 메시지 전송 webSocketClient.publish({ destination: '/app/' + roomId.id, // 채팅방 주소, body: JSON.stringify({ // userId랑 메시지 내용만 보내기 - 서버에서 정해줌 userId: userId, message: message }) }); webSocketClient.publish({ destination: '/topic/room/' + roomId.id, // 채팅방 주소, body: JSON.stringify({ chatId: Math.random(), localTime: new Date(), msg: message, responseDto: { id: userId, nickname: userId } }) }); setMessage(''); // 메시지 초기화 } } else { setHasInputError(true); } };
-
미해결[입문자를 위한 UE5] Part5. 언리얼 엔진 VR
잡기 애니메이션 부분에서 오른손이 동작을 안합니다.
IMC 상태입니다. 애니메이션 블루프린트에서 PoseAlphaGrasp 값을 찍으면서 A,D 를 눌러보면 값이 변하긴 합니다만, 왼손 애니메이션은 출력되지만 오른손 애니메이션은 출력되지 않는 문제가 있습니다. 어떻게 해야 하나요?위 사진은 현재 애니메이션 블루프린트 입니다.
-
미해결
배포 후 소셜 로그인
로컬에서는 구글 소셜로그인이 제대로 돌아가고 로그인시 가입, JWT 발급까지 제대로 돌아가는데 프로젝트를 EC2에 배포하고 개발자센터에 승인된 URI에 등록하고 yml에 redirect-uri 똑같이 등록을 했는데 배포시에는 에러가 발생합니다.발생한 에러:구글 아이디들이 나오기는 하는데 클릭을 하면이 에러가 발생합니다. 이게 로컬에서도 안되면 이해가 가는데 로컬에서는 에러없이 잘돌아갑니다. 대체 무슨 문제일까요... ㅠㅠ 급합니다.