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 { fetchWithCred } from '../../lib/api'
|
||||||
import { authUrl } from '../../lib/endpoints'
|
import { authUrl } from '../../lib/endpoints'
|
||||||
import { useAuth } from '../../app/providers/AuthProvider'
|
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() {
|
export default function Login() {
|
||||||
const { login } = useAuth()
|
const { login } = useAuth()
|
||||||
|
|
||||||
|
|
@ -13,6 +20,19 @@ export default function Login() {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [error, setError] = useState(null)
|
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) => {
|
const handleChange = (e) => {
|
||||||
setForm({
|
setForm({
|
||||||
...form,
|
...form,
|
||||||
|
|
@ -48,6 +68,11 @@ export default function Login() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleGoogleLogin = () => {
|
||||||
|
// fetch 아님! 전체 페이지 이동 (Google 리다이렉트 흐름)
|
||||||
|
window.location.href = authUrl('/oauth2/authorization/google')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="login-box" onSubmit={handleLogin}>
|
<form className="login-box" onSubmit={handleLogin}>
|
||||||
<h2 className="login-title">GREEN FIELD</h2>
|
<h2 className="login-title">GREEN FIELD</h2>
|
||||||
|
|
@ -80,6 +105,17 @@ export default function Login() {
|
||||||
>
|
>
|
||||||
{loading ? 'Signing in...' : 'Login'}
|
{loading ? 'Signing in...' : 'Login'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div className="login-divider"><span>또는</span></div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="login-button login-google"
|
||||||
|
onClick={handleGoogleLogin}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Google로 로그인
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,8 @@ export default function CsHomePage() {
|
||||||
{custErr && <span className="cshome-section-note">고객 요약 미연동 · {custErr}</span>}
|
{custErr && <span className="cshome-section-note">고객 요약 미연동 · {custErr}</span>}
|
||||||
</div>
|
</div>
|
||||||
<div className="cshome-grid cshome-grid-2">
|
<div className="cshome-grid cshome-grid-2">
|
||||||
<Card label="전체 고객 수" value={fmt(cust?.total)} unit="명" />
|
<Card label="전체 고객 수" value={fmt(cust?.total)} unit="곳" />
|
||||||
<Card label="오늘 추가된 고객" value={fmt(cust?.today)} unit="명" accent />
|
<Card label="오늘 추가된 고객" value={fmt(cust?.today)} unit="곳" accent />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,3 +120,31 @@ button {
|
||||||
text-align: center;
|
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