📃 요약
Multi-provider social login 샘플입니다.
구글 로그인 , 네이버 로그인을 이용해서 진행해 보도록 하겠습니다.
구글 클라우드에 API 신청 및 clientId, clientSecret 로 springboot 에 설정합니다.
마찬가지로, 네이버 디벨로퍼 사이트에서 API 신청 및 clientId, clientSecret 로 springboot 에 설정합니다.
소셜 로그인할 때 DB 에 소셜로그인 사용자를 저장해 보겠습니다.
다중 공급자일때는 어떻게 구현하는지를 보시면 되겠습니다.
글에 언급되지 않는 일반 로그인 소스가(Spring Security) 포함되어 있습니다.
구글 / 네이버 로그인 등록은 생략하겠습니다.
구글 / 네이버 로그인 등록에 관한 것은 아래 주소를 참고하세요
( 참조 블로그 : https://deeplify.dev/back-end/spring/oauth2-social-login )
프론트는 Vue 를 사용하고, 벡엔드는 spring boot 를 사용합니다.
DB 는 오라클 도커 이미지를 사용하고 계정은 scott ( 암호 : !Ds1234567890 ) 개발자 계정을 생성하고 사용합니다.
DB 개발자 계정 및 설치하는 방법은 생략합니다.
요소 기술 :
– 프론트엔드 : Vue
– 벡엔드 : Spring Boot & JPA
– DB : Oracle 18xe(Docker)
( Oracle 18xe 도커 이미지 주소 : https://hub.docker.com/r/kangtaegyung/oraclexe-18c )
결과 화면 :
- 로그인 화면

- 구글 계정 선택 화면 #1

- 구글 계정 선택 화면 #2

- Home 화면 이동

- 구글 로그인 완료 후 새로운 구글 사용자 테이블에 저장됨

프로젝트 탐색기 : Vue

프로젝트 탐색기 : String Boot

Front : 소셜 로그인 url 정보
| 메소드 | URL | 설명 |
|---|---|---|
| GET | http://localhost:8000/oauth2/code/google | LoginView.vue 구글 로그인 버튼 클릭시 실행될 주소 구글 클라우드에서 등록된 승인된 리다이렉트 URL 주소 |
| GET | /auth-redirect | SocialRedirectView.vue 벡엔드에서 보내준 웹토큰, 유저정보를 로컬스토리지에 저장하고 동시에 Home 으로 강제 이동함 |
Backend : 소셜 로그인 URL 정보
| 메소드 | URL | 설명 |
|---|---|---|
| GET | http://localhost:8080/auth-redirect | SocialLoginSuccess.java 소셜로그인 성공후 Vue 리다이렉트 주소로 웹토큰, 유저정보 전송할 URL 정보 |
소셜 로그인 간단 절차
- 1) 로그인 버튼 클릭 : 소셜 로그인 사이트에서 제공된 URL 입니다.
- 구글 : http://벡엔드주소/oauth2/authorization/google
- 네이버 : http://벡엔드주소/oauth2/authorization/naver
- 2) 로그인 자동 인증 : 스프링 OAuth 패키지가 소셜 로그인 공급자에게 받은 인가코드로 인증 토큰을 자동적으로 받아옵니다.
- 3) 인증 토큰을 받은 후 추가 로직을 개발자가 구현합니다.
- DB 에 새 사용자 저장
- Vue 로 웹토큰(JWT) , 사용자 부가 정보 전송

📃 기술 구현
스펙 :
테이블 설계
DROP TABLE TB_MEMBER CASCADE CONSTRAINTS;
CREATE TABLE TB_MEMBER
(
EMAIL VARCHAR2(1000) NOT NULL PRIMARY KEY, -- id (email)
PASSWORD VARCHAR2(1000), -- 암호
NAME VARCHAR2(1000), -- 유저명
CODE_NAME VARCHAR2(1000), -- 권한코드명(ROLE_USER, ROLE_ADMIN)
DELETE_YN VARCHAR2(1) DEFAULT 'N',
INSERT_TIME VARCHAR2(255),
UPDATE_TIME VARCHAR2(255),
DELETE_TIME VARCHAR2(255)
);
소셜 로그인 구현을 위한 테이블 설계입니다.
데이터베이스를 오라클(Docker)을 사용하여 구현해 보겠습니다.
Spring build.gradle : dependencies 블럭 내 추가
dependencies {
// OAUTH2 라이브러리 추가 : 소셜 로그인 등 클라이언트 입장에서 소셜 기능 구현 시 필요한 의존성
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
... 생략
}
Spring Security 설정 클래스
-WebSecurityConfig.java
package org.example.simpledms.config;
import jakarta.servlet.DispatcherType;
import lombok.RequiredArgsConstructor;
import org.example.simpledms.security.oauth.SocialLoginSuccess;
import org.example.simpledms.security.oauth.SocialLoginServiceCustom;
import org.example.simpledms.security.jwt.AuthTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @fileName : WebSecurityConfig
* @author : GGG
* @since : 2024-04-15
* description :
* 1) DB 인증을 위한 함수 : passwordEncoder()
* 2) 패스워드 암호화 함수 : 필수 정의
* @Bean : IOC (스프링이 객체를 생성해주는 것), 함수의 리턴객체를 생성함
* => (참고) 용어 : 스프링 생성한 객체 == 빈(Bean==콩)
* 3) JWT 웹토큰 자동인증 함수 : authenticationJwtTokenFilter()
* 4) img, css, js 등 인증 무시 설정 함수 : webSecurityCustomizer()
* => 사용법 : (web) -> web.ignoring().requestMatchers("경로", "경로2"...)
* 5) 스프링 시큐리티 규칙 정의 함수(***) : filterChain(HttpSecurity http)
* 5-1) cors 사용
* 5-2) csrf 해킹 보안 비활성화(쿠키/세션 사용않함)
* 5-3) 쿠키/세션 안함(비활성화) -> 로컬스토리지/웹토큰
* 5-4) form 태그 action 을 이용한 로그인 사용않함 -> axios 통신함
* 5-5) /api/auth/** : 이 url 은 모든 사용자 접근 허용, ** (하위 url 모두 포함)
* 5-8) / : 이 url 은 모든 사용자 접근 허용
* 5-9) TODO : 웹토큰 클래스를 스프링시큐리티 설정에 끼워넣기 : 모든 게시판 조회(CRUD)에서 아래 인증을 실행함
*
* 6) 소셜 로그인
* 6-1) 소셜 로그인 성공후 처리할 리다이렉션해서 구글 인가코드 받음
* 6-2) 구글 인가코드 확인 후에 DB 인증, 웹토큰 발행, 프론트로 전송
*/
@Configuration
@RequiredArgsConstructor
public class WebSecurityConfig {
private final SocialLoginSuccess socialLoginSuccess;
private final SocialLoginServiceCustom socialLoginServiceCustom ;
private final AuthTokenFilter authTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// img, css, js 등 인증 무시 설정 함수
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(
"/img/**",
"/css/**",
"/js/**"
);
}
// TODO: 스프링 시큐리티 규칙 정의 함수(***)
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors(Customizer.withDefaults()); // 5-1)
http.csrf((csrf) -> csrf.disable()); // 5-2)
http.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 5-3)
http.formLogin(req -> req.disable()); // 5-4)
http.authorizeHttpRequests(req -> req
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.requestMatchers("/api/auth/**").permitAll() // 5-5)
.requestMatchers("/").permitAll() // 5-8)
.anyRequest()
.authenticated());
// TODO: 소셜 로그인 설정 부분
http.oauth2Login(req -> req
.successHandler(socialLoginSuccess) // 6-1)
.userInfoEndpoint(arg -> arg.userService(socialLoginServiceCustom)) // 6-2)
);
// 5-9)
http.addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
- TODO: 소셜 로그인 설정 부분이 Spring Security 에서 설정할 부분입니다.
- socialLoginSuccess : 성공후에 실행될 클래스이고, Vue 로 웹토큰 , 유저정보를 전송합니다.
- socialLoginServiceCustom : 구글, 네이버 인증토큰을 받으면 실행될 클래스 이고, DB 에 새로운 소셜 사용자를 등록합니다.
소셜 로그인 클래스 : 구글 API 인가토큰을 받아 인증 처리 하는 클래스
-SocialLoginServiceCustom.java
package org.example.simpledms.security.oauth;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.simpledms.model.entity.auth.Member;
import org.example.simpledms.repository.auth.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import java.util.Collections;
/**
* @fileName : SocialLoginServiceCustom
* @author : kangtaegyung
* @since : 2022/12/16
* description :
* 알고리즘
* 1) OAuth2UserService : 유저정보 있는 클래스
* 2) registrationId : google, naver, kakao 같은 이름이 있음, 이것으로 각 서비스를 구분함
* 3) OAuth2 로그인 진행시 키가 되는 필드값, 인증토큰(PK 와 같음)
* 4) registrationId 에 따라 구글함수, 네이버함수, 카카오함수를 실행하는 함수
* 5) 소셜 기본정보 DB 저장, 유저가 있으면 무시
* 6) 소셜유저 생성 및 내보내기
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SocialLoginServiceCustom implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final MemberRepository memberRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService<OAuth2UserRequest, OAuth2User> socialLoginService = new DefaultOAuth2UserService(); // 1)
OAuth2User socialLogin = socialLoginService.loadUser(userRequest);
String registrationId = userRequest.getClientRegistration().getRegistrationId(); // 2)
String socialKey = userRequest.getClientRegistration().getProviderDetails()
.getUserInfoEndpoint().getUserNameAttributeName(); // 3)
SocialProviders socialProviders = SocialProviders.of(registrationId, socialKey, socialLogin.getAttributes()); // 4)
saveSocialIdOrSkip(socialProviders); // 5)
return new DefaultOAuth2User( // 6)
Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")),
socialProviders.getSocialUser(),
socialProviders.getSocialKey());
}
private void saveSocialIdOrSkip(SocialProviders socialProviders) {
try {
if(memberRepository.existsById(socialProviders.getEmail()) == false) {
memberRepository.save(socialProviders.getDefaultUser());
}
} catch (Exception e) {
log.debug("saveSocialIdOrSkip 에러" ,e.getMessage());
}
}
}
- 구글 / 네이버 로그인 성공 후 인증토큰을 받으면(자동) 벡엔드에서 새로운 사용자로 DB 에 저장합니다.
- 구글, 네이버 인가코드를 통한 인증토큰은 OAuth 스프링 라이브러리가 자동적으로 처리하고 인증토큰을 받아옵니다
- 개발자는 구글 / 네이버 로그인이 정상적으로 진행되었다는 가정하에 (인증토큰 받음) 추가 로직을 작성하면 됩니다. 여기서는 DB 에 사용자를 저장합니다.
- DB 에 저장시 기본정보로 저장합니다.
– SocialLoginSuccess.java
DB 에 사용자 저장 후에 실행될 클래스 : 웹토큰 발급 및 프론트로 유저 정보 전송
package org.example.simpledms.security.oauth;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.simpledms.security.jwt.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @fileName : SocialLoginSuccess
* @author : kangtaegyung
* @since : 2022/12/16
* description : 소셜 로그인 성공 후 처리할 클래스
* 알고리즘
* 1) 인증된 객체를 홀더에 저장
* 2) 인증된 유저 정보를 oAuth2User(소셜로그인 클래스) 에 저장, 소셜로그인은 oAuth2User 사용
* 3) 권한 정보 가져오기
* 4) provider 정보 : google, naver, kakao
* 5) 구글/네이버 등 provider 마다 전달해주는 속성명과 구조가 틀림
* 구글 : { email: forbob@naver.com , name: 강태경 }
* 네이버 : { response : { email: forbob@naver.com , id : abcdef } }
* 6) 토큰 발행
* 7) 리다이렉션 페이지로 이동 : vue 로 jwt , 유저정보를 전송함
* <p>
* 참고) 함수
* - UriComponentsBuilder.fromUriString("기본url")
* .queryParam("키", 값) // 쿼리스트링 변수명, 값
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class SocialLoginSuccess extends SimpleUrlAuthenticationSuccessHandler {
private final JwtUtils jwtUtils;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
SecurityContextHolder.getContext().setAuthentication(authentication); // 1)
OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal(); // 2)
List<GrantedAuthority> authorities = new ArrayList(authentication.getAuthorities());
String codeName = authorities.get(0).toString(); // 3) 권한
String email = "";
OAuth2AuthenticationToken authToken = (OAuth2AuthenticationToken) authentication; // 4) provider 정보
switch (authToken.getAuthorizedClientRegistrationId()) { // 5)
case "google":
Map<String, Object> googleUser = oAuth2User.getAttributes();
email = (String) googleUser.get("email");
break;
case "naver":
Map<String, Object> naverUser = (Map<String, Object>) oAuth2User.getAttributes().get("response");
email = (String) naverUser.get("email");
break;
}
String jwt = jwtUtils.generateJwtToken(email); // 6)
String targetUrl = UriComponentsBuilder.fromUriString("http://localhost:8080/auth-redirect") // 7)
.queryParam("accessToken", jwt)
.queryParam("email", email)
.queryParam("codeName", codeName)
.build().toUriString();
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}
- DB 에 새사용자가 저장되면 웹토큰을 발급해서 프론트로 유저정보와 함께 전송합니다.
- 프론트 전송 주소는 http://localhost:8080/auth-redirect 입니다.
- 웹토큰, email, codeName(권한) 정보를 쿼리스트링 방식으로 전송합니다.
– SocialProviders
구글 / 네이버 로그인 ( Providers ) 에 따라 해당되는 함수가 실행될 수 있도록 작성된 클래스
package org.example.simpledms.security.oauth;
import lombok.Builder;
import lombok.Getter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.example.simpledms.model.entity.auth.Member;
import java.util.Map;
/**
* @fileName : SocialProviders
* @author : kangtaegyung
* @since : 2022/12/16
* description : name 는 email 의 @ 앞부분을 잘라서 저장
* 각각 : email 저장된 속성명
* google : (String) socialUser.get("email")
* naver : Map<String, Object> response = (Map<String, Object>) socialUser.get("response") 안에 email 속성이 있음
* (String) response.get("email")
* kakao : (String) socialUser.get("account_email")
*/
@Getter
public class SocialProviders {
PasswordEncoder encoder = new BCryptPasswordEncoder();
private Map<String, Object> socialUser;
private String socialKey;
private String name;
private String email;
@Builder
public SocialProviders(Map<String, Object> socialUser,
String socialKey, String name,
String email) {
this.socialUser = socialUser;
this.socialKey = socialKey;
this.name = name;
this.email = email;
}
// registrationId 를 체크해서 구글 / 네이버 / 카카오 정보 가져오기
public static SocialProviders of(String registrationId,
String nameAttributeName,
Map<String, Object> socialUser) {
switch (registrationId) {
case "google":
return ofGoogle(nameAttributeName, socialUser);
case "naver":
return ofNaver(nameAttributeName, socialUser);
case "kakao":
return ofKakao(nameAttributeName, socialUser);
default:
return ofGoogle(nameAttributeName, socialUser);
}
}
private static SocialProviders ofGoogle(String nameAttributeName,
Map<String, Object> socialUser) {
return SocialProviders.builder()
.name(((String) socialUser.get("email")).split("@")[0])
.email((String) socialUser.get("email"))
.socialUser(socialUser)
.socialKey(nameAttributeName)
.build();
}
private static SocialProviders ofNaver(String nameAttributeName,
Map<String, Object> socialUser) {
Map<String, Object> response = (Map<String, Object>) socialUser.get("response");
return SocialProviders.builder()
.name(((String) response.get("email")).split("@")[0])
.email((String) response.get("email"))
.socialUser(socialUser)
.socialKey(nameAttributeName)
.build();
}
private static SocialProviders ofKakao(String nameAttributeName,
Map<String, Object> socialUser) {
Map<String, Object> kakaoAccount = (Map<String, Object>) socialUser.get("kakao_account");
return SocialProviders.builder()
.name(((String) kakaoAccount.get("email")).split("@")[0])
.email((String) kakaoAccount.get("email"))
.socialUser(socialUser)
.socialKey(nameAttributeName)
.build();
}
// OAuthsocialUser에서 엔티티를 생성하는 시점은 처음 가입할 때
// User 엔티티를 생성
public Member getDefaultUser() {
return Member.builder()
.name(this.email)
.email(this.email)
.password(encoder.encode("123456"))
.codeName("ROLE_USER")
.build();
}
}
- registrationId : 구글 인지 네이버 공급자( Providers ) 인지 알려주는 변수입니다.
- 공급자가 인증토큰과 함께 전송해 줍니다.
- 저장된 값은 google 또는 naver 가 저장되어 있습니다.
Vue 페이지 :
프론트는 로그인 버튼에 네이버 인증 요청 링크를 추가하는 것 외에 싱글 공급자 로그인 예제와 거의 동일합니다.
– Vue 패키지 추가 :
npm i axios
1) 공통 js
– utils/axiosDefaultConfig.js : axios 기본 설정 파일
import axios from "axios";
// axios 기본 설정
export default axios.create({
baseURL: "http://localhost:8000/api",
headers: {
"Content-Type": "application/json"
}
});
– router/index.js
import { createRouter, createWebHistory } from "vue-router";
const routes = [
{
path: "/",
component: () => import("../views/HomeView.vue"),
},
// 로그인
{
path: "/login",
component: () => import("../views/auth/LoginView.vue"),
},
// 회원가입
{
path: "/register",
component: () => import("../views/auth/RegisterView.vue"),
},
// 소셜 로그인
{
path: "/auth-redirect",
component: () => import("../views/auth/SocialRedirectView.vue"),
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
Vue 페이지
로그인 결과 화면 :

– views/auth/LoginView.vue
<!-- 사용법 : @submit.prevent="함수" -->
<!-- prevent : submit 의 기본 속성을 막기(다른 곳으로 이동하려는 특징) -->
<template>
<div>
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card mt-5">
<div class="card-body p-0">
<!-- {/* Nested Row within Card Body */} -->
<div class="row">
<div class="col-lg-6 bg-login-image"></div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 mb-4">Welcome Back!</h1>
</div>
<form class="user" @submit.prevent="login">
<div class="form-group">
<input
type="email"
class="form-control form-control-user mb-3"
placeholder="이메일을 넣기"
name="email"
v-model="user.email"
/>
</div>
<div class="form-group">
<input
type="password"
class="form-control form-control-user mb-3"
placeholder="패스워드 넣기"
name="password"
v-model="user.password"
/>
</div>
<button class="btn btn-primary btn-user w-100 mb-3">
Login
</button>
<hr />
<a
href="http://localhost:8000/oauth2/authorization/google"
class="btn btn-google btn-user w-100 mb-2"
>
<i class="fab fa-google fa-fw"></i> Login with Google
</a>
<a href="http://localhost:8000/oauth2/authorization/naver" class="btn btn-naver btn-user w-100 mb-2">
<i class="fa-solid fa-n"></i> Login with Naver
</a>
<a href="/" class="btn btn-kakao btn-user w-100 mb-3">
<i class="fa-solid fa-k"></i> Login with Kakao
</a>
</form>
<hr />
<div class="text-center">
<a class="small" href="/forgot-password">
Forgot Password?
</a>
</div>
<div class="text-center">
<a class="small" href="/register"> Create an Account! </a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// TODO: 1) spring 보내준 user 객체(웹토큰있음)를 로컬스토리지에 저장
// TODO: 사용법 : localStorage.setItem(키, 값);
// TODO: => 단, 값은 문자열만 저장됨
// TODO: 사용법 : JSON.stringify(객체) => 문자열로 바뀐 객체가 리턴됨
// TODO: 2) 공유저장소의 state / mutations 함수 접근법
// TODO: mutations 사용법 : this.$store.commit("함수명", 저장할객체)
// TODO: => 로그인성공 공유함수(loginSuccess(state, 유저객체)) 실행
// TODO: state 사용법 : this.$store.state.공유속성명
// TODO: => 공유저장소의 공유속성 접근법
// TODO: 3) 뷰의 라이프사이클
// TODO: - mounted() : 화면이 뜰때 자동 실행 (생명주기 함수)
// TODO: - created() : 뷰가 생성될대 자동 실행
// TODO: - created()(1번, 뷰만 생성되면 실행) -> mounted()(2번, html 태그까지 모두 뜰때)
// TODO: 예) destoryed() : 뷰가 삭제될때 실행 (거의 사용 않함)
import AuthService from "@/services/auth/AuthService";
export default {
data() {
return {
user: {
email: "", // 로그인ID
password: "",
},
};
},
methods: {
async login() {
try {
let response = await AuthService.login(this.user);
console.log(response.data);
localStorage.setItem("user", JSON.stringify(response.data)); // 1)
this.$store.commit("loginSuccess", response.data); // 2)
this.$router.push("/");
} catch (e) {
this.$store.commit("loginFailure");
console.log(e);
}
},
},
// 화면이 뜰때 실행되는 함수
created() {
if (this.$store.state.loggedIn == true) {
// 로그인 상태이면 로그인 불필요
this.$router.push("/");
}
},
};
</script>
<style>
@import "@/assets/css/login.css";
</style>
- 로그인 버튼 url : 구글 API 주소 (http://localhost:8000/oauth2/code/google)
- 상기 주소를 구글 로그인 API 신청 시 클라우드 사이트에 등록해야 합니다.
Vue 리다이렉트 페이지
– views/auth/SocialRedirectView.vue
<!-- 소셜로그인 리다이렉트 페이지 -->
<template>
<div >
</div>
</template>
<script>
export default {
data() {
return {
user: {},
};
},
mounted() {
let url = new URL(window.location.href);
console.log(url);
const urlParams = url.searchParams; // uri 정보 가져오기
const accessToken = urlParams.get("accessToken");
const email = urlParams.get("email");
const codeName = urlParams.get("codeName");
this.user = {
accessToken: accessToken,
email: email,
codeName: codeName,
};
console.log("social user", this.user);
localStorage.setItem("user", JSON.stringify(this.user));
this.$store.commit('loginSuccess', this.user);
this.$router.push("/");
},
};
</script>
- 벡엔드에서 소셜 로그인 성공하면 Vue. 로 웹토큰, 유저정보를 보내줍니다.
- 로컬스토리지에 유저정보를 저장하고, Home 으로 강제 페이지 이동 시킵니다.
📃 결론
구글 / 네이버 로그인을 이용해서 소셜 로그인을 진행하는 예제를 살펴보았습니다.
구글 로그인 버튼을 클릭하면 구글 로그인 url 로 이동되고, 네이버 로그인 버튼을 클릭하면 네이버 로그인 url 로 이동됩니다.
구글 / 네이버 인증이 완료되면 인증토큰을 springboot 으로 전송합니다.
인가코드 및 인증토큰을 받는 로직은 OAuth 스프링 패키지가 자동적으로 처리합니다.
개발자는 인증토큰을 받은 후에 새 사용자를 DB 에 생성하고 웹토큰을 vue 전송하는 로직만 작성합니다.
Spring Boot 는 @RestController 어노테이션을 이용해 구현했으며, 결과는 JSON 데이터로 리턴됩니다.
Vue 는 axios 라이브러리를 사용해 벡엔드와 통신합니다.
DB 프레임워크는 JPA 를 이용해서 sql 문을 직접 제작하지 않고 자동화기능을 이용해 구현했습니다.
다중 로그인에 관심 있으시다면 Source 는 아래에서 찾을 수 있습니다.
감사합니다.



