Laravel
Laravel + nuxt 소셜로그인 #sanctum #social #로그인 #소셜 #vue #nuxt #api
짱구를왜말려?
2023. 3. 23. 22:50
반응형
SMALL
# What?
- API 방식으로 소셜로그인 구현하는 방법
# How?
- 기본원리
-> 클라이언트 서버쪽에서 API 서버쪽으로 redirect
-> API 서버에서 소셜로그인 후 callback 받기
-> callback 받은 후 로그인 or 가입처리 후 토큰생성 후 클라이언트쪽에 토큰값 넘겨주기
-> 클라이언트쪽에서 socialLogin페이지 따로 만들어놓고 token params받아 로그인 시도하기
-> API쪽에서 login 메소드에 token으로 로그인 요청 있는지를 확인하여 유저정보 및 token값 리턴하기
-> 클라이언트쪽에서 해당 정보로 로그인처리 완료하기
1. 백엔드 세팅
- 백엔드 sanctum 세팅 (sanctum글 참고)
- .env 세팅 -> 프론트 서버 url 및 소셜키값 세팅
@ .env
APP_CLIENT_URL=http://localhost:3000
@ app.php
'client_url' => env('APP_CLIENT_URL', 'https://whatpick.com'),
- 컨트롤러 세팅
@ Api/UserController - login과, socialLogin 메소드가 핵심
public function login(Request $request)
{
// 소셜로그인 시도 시
if($request->token && auth()->user()){
return $this->respondSuccessfully([
"token" => $request->token,
"user" => UserResource::make(auth()->user())
]);
}
$data = $request->validate([
"ids" => "required|string|max:500",
"password" => "required|string|max:500",
]);
if(auth()->attempt($request->only("ids", "password"))) {
session()->regenerate();
$token = auth()->user()->createToken("auth");
return $this->respondSuccessfully([
"token" => $token->plainTextToken,
"user" => UserResource::make(auth()->user())
]);
}
return throw ValidationException::withMessages([
"ids" => [
__("socialLogin.invalid")
]
]);
}
public function openSocialLoginPop($social)
{
return Socialite::driver($social)->stateless()->redirect();
}
public function socialLogin(Request $request, $social)
{
$socialUser = Socialite::driver($social)->stateless()->user();
// 일단 네이버
$user = User::where("social_id", $socialUser->id)->where("social_platform", $social)->first();
if(!$user) {
$user = User::create([
"name" => $social,
"social_id" => $socialUser->id,
"social_platform" => $social
]);
}
$token = $user->createToken("auth")->plainTextToken;
Auth::login($user);
return redirect(config("app.client_url")."/socialLogin?token=".$token);
}
- 프론트 세팅
@ socialLogin.vue
<template>
</template>
<script>
export default {
data(){
return {
token: this.$route.query.token ? this.$route.query.token : null,
}
},
mounted() {
this.$auth.loginWith('laravelSanctum', {
data: {
token:this.token
}
}).then(response => {
this.$router.back();
}).catch((e) => {
alert("소셜로그인에 실패하였습니다.");
return this.$router.push("/");
})
}
}
</script>
@ login.vue
<template>
<main class="login">
<div class="container col-group">
<div class="left-wrap row-group">
<div class="login-wrap">
<form @submit.prevent="login" @keydown="() => {form.errors.clear()}">
<h2 class="login-title scd6">
<span class="scd6">왓픽</span> 회원 로그인
</h2>
<div class="login-form row-group">
<input type="text" placeholder="아이디를 입력해 주세요." v-model="form.ids">
<p class="m-input-error" v-if="form.errors.has('ids')">{{form.errors.get("ids")}}</p>
<input type="password" placeholder="비밀번호를 입력해 주세요." v-model="form.password">
<p class="m-input-error" v-if="form.errors.has('password')">{{form.errors.get("password")}}</p>
<button type="submit" class="login-submit scd5">로그인</button>
<div class="col-group">
<label for="auto_login">
<input type="checkbox" id="auto_login">
<span class="check-icon"></span>
자동로그인
</label>
<div class="find-account col-group">
<a href="find_id1.html">아이디 찾기</a>
<a href="find_pw1.html">비밀번호 찾기</a>
</div>
</div>
</div>
<div class="sns-login-wrap col-group">
<p class="title">
<strong>SNS</strong> 계정 로그인
</p>
<ul class="sns-login-list col-group">
<li>
<a :href="`${$store.state.domain}/openLoginPop/naver`">
<img src="/images/sns_login_naver.png" alt="">
</a>
</li>
<li>
<a :href="`${$store.state.domain}/openLoginPop/kakao`">
<img src="/images/sns_login_kakao.png" alt="">
</a>
</li>
<li>
<a :href="`${$store.state.domain}/openLoginPop/google`">
<img src="/images/sns_login_facebook.png" alt="">
</a>
</li>
<li>
<a :href="`${$store.state.domain}/openLoginPop/facebook`">
<img src="/images/sns_login_google.png" alt="">
</a>
</li>
</ul>
</div>
</form>
</div>
<a href="join.html" class="join-wrap col-group">
<div class="txt-box">
<h3 class="join-title scd5">아직 회원이 아니신가요?</h3>
<p class="title">
<span class="red scd5">회원가입</span> 후 다양한 서비스를 만나보세요
</p>
</div>
<i class="xi-arrow-right"></i>
</a>
</div>
<div class="right-wrap">
<div class="txt-box">
<span class="notice">
<i class="xi-info"></i>
</span>
<p class="title">
왓픽은 중고차 <span class="scd5">구매 도우미</span> 입니다.
</p>
<p class="txt">
왓픽은 중고차를 판매하지 않습니다. 왓픽은 중고차 매물의 진짜 정보를 제공합니다.
</p>
</div>
<img src="/images/login_bg.png" alt="">
</div>
</div>
</main>
</template>
<script>
import Form from "../utils/Form";
export default {
name: 'Login',
data(){
return {
form : new Form(this.$axios, {
ids:"",
password:""
})
}
},
methods: {
login(){
this.$auth.loginWith('laravelSanctum', {
data: this.form.data()
});
/*this.$axios.get('/sanctum/csrf-cookie').then(response => {
this.form.post("/api/login")
.then(response => {
this.$axios.defaults.headers.common["Authorization"] = `Bearer ${response.data.token}`;
this.$store.commit("setToken", response.data.token);
this.$store.commit("setUser", response.data.user);
console.log(this.$store.state.user);
})
.catch(error => {
})
});*/
}
}
}
</script>
* 실 배포 후 필수세팅
SESSION_DOMAIN=.whatpick.com // 본 도메인
SANCTUM_STATEFUL_DOMAINS=whatpick.com // 클라이언트 도메인
LIST