Google Workspace OAuth2 적용
This commit is contained in:
parent
7d7e6607f8
commit
d71cec4709
|
|
@ -1,8 +1,15 @@
|
|||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { fetchWithCred } from '../../lib/api'
|
||||
import { authUrl } from '../../lib/endpoints'
|
||||
import { useAuth } from '../../app/providers/AuthProvider'
|
||||
|
||||
// OAuth2 성공 핸들러가 실패 시 ?login_error=코드 로 돌려보낸다.
|
||||
const LOGIN_ERROR_MESSAGES = {
|
||||
not_registered: '등록되지 않은 계정입니다. 관리자에게 문의하세요.',
|
||||
domain_not_allowed: 'greenoilinc.com 계정으로만 로그인할 수 있습니다.',
|
||||
inactive: '비활성화된 계정입니다. 관리자에게 문의하세요.',
|
||||
}
|
||||
|
||||
export default function Login() {
|
||||
const { login } = useAuth()
|
||||
|
||||
|
|
@ -13,6 +20,19 @@ export default function Login() {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
// 리다이렉트로 돌아온 OAuth 로그인 에러 표시
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const code = params.get('login_error')
|
||||
if (code) {
|
||||
setError(LOGIN_ERROR_MESSAGES[code] ?? '로그인에 실패했습니다.')
|
||||
// 주소창에서 쿼리 제거 (새로고침 시 에러가 남지 않도록)
|
||||
params.delete('login_error')
|
||||
const clean = window.location.pathname + (params.toString() ? `?${params}` : '')
|
||||
window.history.replaceState({}, '', clean)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleChange = (e) => {
|
||||
setForm({
|
||||
...form,
|
||||
|
|
@ -22,7 +42,7 @@ export default function Login() {
|
|||
|
||||
const handleLogin = async (e) => {
|
||||
// enter 키에 페이지 리로드막고 직접 처리
|
||||
e.preventDefault()
|
||||
e.preventDefault()
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
|
@ -48,6 +68,11 @@ export default function Login() {
|
|||
}
|
||||
}
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
// fetch 아님! 전체 페이지 이동 (Google 리다이렉트 흐름)
|
||||
window.location.href = authUrl('/oauth2/authorization/google')
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="login-box" onSubmit={handleLogin}>
|
||||
<h2 className="login-title">GREEN FIELD</h2>
|
||||
|
|
@ -80,6 +105,17 @@ export default function Login() {
|
|||
>
|
||||
{loading ? 'Signing in...' : 'Login'}
|
||||
</button>
|
||||
|
||||
<div className="login-divider"><span>또는</span></div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="login-button login-google"
|
||||
onClick={handleGoogleLogin}
|
||||
disabled={loading}
|
||||
>
|
||||
Google로 로그인
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,8 +146,8 @@ export default function CsHomePage() {
|
|||
{custErr && <span className="cshome-section-note">고객 요약 미연동 · {custErr}</span>}
|
||||
</div>
|
||||
<div className="cshome-grid cshome-grid-2">
|
||||
<Card label="전체 고객 수" value={fmt(cust?.total)} unit="명" />
|
||||
<Card label="오늘 추가된 고객" value={fmt(cust?.today)} unit="명" accent />
|
||||
<Card label="전체 고객 수" value={fmt(cust?.total)} unit="곳" />
|
||||
<Card label="오늘 추가된 고객" value={fmt(cust?.today)} unit="곳" accent />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -120,3 +120,31 @@ button {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
/* google login */
|
||||
.login-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: #9aa0a6;
|
||||
font-size: 12px;
|
||||
}
|
||||
.login-divider::before,
|
||||
.login-divider::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
border-bottom: 1px solid #e3e5e8;
|
||||
}
|
||||
.login-divider span {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.login-google {
|
||||
background: white;
|
||||
color: #3c4043;
|
||||
border: 1px solid #dadce0;
|
||||
}
|
||||
.login-google:disabled {
|
||||
background: #f5f5f5;
|
||||
color: #9aa0a6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
Loading…
Reference in New Issue