google 계정으로 로그인하기 with php

기션·2024년 7월 14일
post-thumbnail

php8 기준, laravel 등의 framework를 사용하지 않고, google 계정으로 로그인 하기

특징
. claude의 도움을 받음.
. php에서 composer나 link등을 사용하지 않고 sub folder에 파일만 복사함으로 간단하게 실행되는데 중점을 둠.

!Google Console에서 사용자 인증 정보의 승인된 리디렉션 uri를 반드시 기록해야 함

OAuth동의 화면은 External 타입으로 만들고 테스트 사용자에 테스트할 자기 계정을 넣어야 함.

다음은 claude ai 내용 -
물론입니다. 프레임워크를 사용하지 않고 순수한 PHP로 같은 기능을 구현할 수 있습니다. 아래에 프레임워크 없이 구현한 예제 코드를 제공해 드리겠습니다.
프로젝트 구조:
Copyproject/
├── public/
│ └── index.php
├── src/
│ ├── auth.php
│ ├── admin.php
│ ├── user.php
│ ├── database.php
│ └── config.php
├── templates/
│ ├── login.php
│ ├── admin.php
│ └── user.php
└── composer.json (Google API Client용)
composer.json:
jsonCopy{
"require": {
"google/apiclient": "^2.0"
}
}
public/index.php:

session_start();
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../src/config.php';
require_once __DIR__ . '/../src/database.php';
require_once __DIR__ . '/../src/auth.php';
require_once __DIR__ . '/../src/admin.php';
require_once __DIR__ . '/../src/user.php';

$request_uri = $_SERVER['REQUEST_URI'];

switch ($request_uri) {
    case '/':
        showLoginPage();
        break;
    case '/auth/google':
        handleGoogleAuth();
        break;
    case '/admin':
        if (isAdmin()) {
            showAdminPage();
        } else {
            header('Location: /');
        }
        break;
    case '/admin/sentence':
        if (isAdmin() && $_SERVER['REQUEST_METHOD'] === 'POST') {
            addSentence();
        } else {
            header('Location: /admin');
        }
        break;
    case '/user':
        if (isLoggedIn()) {
            showUserPage();
        } else {
            header('Location: /');
        }
        break;
    case '/user/like':
        if (isLoggedIn() && $_SERVER['REQUEST_METHOD'] === 'POST') {
            likeSentence();
        } else {
            header('Location: /user');
        }
        break;
    default:
        http_response_code(404);
        echo "404 Not Found";
        break;
}

src/config.php:

define('GOOGLE_CLIENT_ID', 'YOUR_GOOGLE_CLIENT_ID');
define('GOOGLE_CLIENT_SECRET', 'YOUR_GOOGLE_CLIENT_SECRET');
define('DB_HOST', 'localhost');
define('DB_NAME', 'your_database_name');
define('DB_USER', 'your_database_user');
define('DB_PASS', 'your_database_password');

src/database.php:

function getDbConnection() {
    static $db = null;
    if ($db === null) {
        $db = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    return $db;
}

src/auth.php:

function showLoginPage() {
    include __DIR__ . '/../templates/login.php';
}

function handleGoogleAuth() {
    $client = new Google_Client();
    $client->setClientId(GOOGLE_CLIENT_ID);
    $client->setClientSecret(GOOGLE_CLIENT_SECRET);
    $client->setRedirectUri('http://your-domain.com/auth/google');
    $client->addScope("email");
    $client->addScope("profile");

    if (isset($_GET['code'])) {
        $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
        $client->setAccessToken($token['access_token']);
        
        $google_oauth = new Google_Service_Oauth2($client);
        $google_account_info = $google_oauth->userinfo->get();
        $email =  $google_account_info->email;
        $name =  $google_account_info->name;

        // 사용자 정보를 데이터베이스에 저장하거나 업데이트
        $db = getDbConnection();
        $stmt = $db->prepare("INSERT INTO users (email, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = ?");
        $stmt->execute([$email, $name, $name]);

        $_SESSION['user_id'] = $db->lastInsertId() ?: $db->query("SELECT id FROM users WHERE email = '$email'")->fetchColumn();
        $_SESSION['user_email'] = $email;
        $_SESSION['user_name'] = $name;

        header('Location: /user');
    } else {
        $auth_url = $client->createAuthUrl();
        header('Location: ' . $auth_url);
    }
}

function isLoggedIn() {
    return isset($_SESSION['user_id']);
}

function isAdmin() {
    return isLoggedIn() && $_SESSION['user_email'] === 'admin@example.com'; // 관리자 이메일을 확인
}

src/admin.php:

function showAdminPage() {
    include __DIR__ . '/../templates/admin.php';
}

function addSentence() {
    $korean = $_POST['korean'] ?? '';
    $english = $_POST['english'] ?? '';
    $korean_file = $_FILES['korean_file']['name'] ?? '';
    $english_file = $_FILES['english_file']['name'] ?? '';

    // 파일 업로드 처리 (실제 구현 시 보안을 위해 추가 검증 필요)
    move_uploaded_file($_FILES['korean_file']['tmp_name'], __DIR__ . '/../uploads/' . $korean_file);
    move_uploaded_file($_FILES['english_file']['tmp_name'], __DIR__ . '/../uploads/' . $english_file);

    $db = getDbConnection();
    $stmt = $db->prepare("INSERT INTO sentences (korean, english, korean_file, english_file) VALUES (?, ?, ?, ?)");
    $stmt->execute([$korean, $english, $korean_file, $english_file]);

    header('Location: /admin');
}

src/user.php:

function showUserPage() {
    $db = getDbConnection();
    $stmt = $db->query("SELECT * FROM sentences");
    $sentences = $stmt->fetchAll(PDO::FETCH_ASSOC);

    include __DIR__ . '/../templates/user.php';
}

function likeSentence() {
    $user_id = $_SESSION['user_id'];
    $sentence_id = $_POST['sentence_id'] ?? 0;

    $db = getDbConnection();
    $stmt = $db->prepare("INSERT INTO likes (user_id, sentence_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE created_at = CURRENT_TIMESTAMP");
    $stmt->execute([$user_id, $sentence_id]);

    header('Location: /user');
}

templates/login.php:

<html>
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login with Google</h1>
    <a href="/auth/google">Login with Google</a>
</body>
</html>
templates/admin.php:
phpCopy<!DOCTYPE html>
<html>
<head>
    <title>Admin Page</title>
</head>
<body>
    <h1>Admin Page</h1>
    <form action="/admin/sentence" method="post" enctype="multipart/form-data">
        <input type="text" name="korean" placeholder="Korean sentence" required>
        <input type="text" name="english" placeholder="English sentence" required>
        <input type="file" name="korean_file">
        <input type="file" name="english_file">
        <button type="submit">Add Sentence</button>
    </form>
</body>
</html>

templates/user.php:

phpCopy<!DOCTYPE html>
<html>
<head>
    <title>User Page</title>
</head>
<body>
    <h1>Welcome, <?php echo htmlspecialchars($_SESSION['user_name']); ?></h1>
    <h2>Sentences</h2>
    <?php foreach ($sentences as $sentence): ?>
        <div>
            <p>Korean: <?php echo htmlspecialchars($sentence['korean']); ?></p>
            <p>English: <?php echo htmlspecialchars($sentence['english']); ?></p>
            <form action="/user/like" method="post">
                <input type="hidden" name="sentence_id" value="<?php echo $sentence['id']; ?>">
                <button type="submit">Like</button>
            </form>
        </div>
    <?php endforeach; ?>
</body>
</html>

이 코드는 프레임워크를 사용하지 않고 순수 PHP로 구현한 예제입니다. 실제 사용 시에는 보안, 에러 처리, 입력 유효성 검사 등을 추가로 구현해야 합니다. 또한, 데이터베이스 스키마를 적절히 설계하고 생성해야 합니다.
이 예제에서는 Google API Client 라이브러리만 사용했습니다. 이 라이브러리는 Google 인증을 쉽게 구현하기 위해 사용되었습니다.
프레임워크를 사용하지 않으면 코드가 더 직관적이고 이해하기 쉬울 수 있지만, 대규모 프로젝트에서는 유지보수와 확장성 측면에서 어려움이 있을 수 있습니다. 프로젝트의 규모와 요구사항에 따라 프레임워크 사용 여부를 결정하시면 됩니다.


sub folder에 놓기 위한 중요 포인트
.htaccess의 RewriteBase부분 - subfolder기록
RewriteBase /app1/
그것때문인지, index.php의 basepath는변경할필요없고base_path는 변경할 필요없고base_path
/app1 은 빼고 넘어온다.

composer.json은 위 내용대로 기록한 후, local pc에서 composer install을 하면 vender 폴더가 생성된다. 이를 복사하면, ssh를 지원하지 않은 웹호스트에서도 사용 가능.

sql

CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `email` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `oauth_provider` enum('google','facebook','github','kakao','naver') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'google',
  `oauth_uid` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `created` datetime DEFAULT current_timestamp(),
  `modified` datetime DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

다음 소스는 참조만 하세요. 깔끔하진 않음
https://koolwind.duckdns.org/index.php/s/i37ZLBtm7Aobtdb

profile
I am a computer programmer fonding of making music(lyrics)

0개의 댓글