Google Sign-In برای برنامه های سمت سرور

برای استفاده از سرویس‌های Google از طرف یک کاربر زمانی که کاربر آفلاین است، باید از یک جریان سمت سرور ترکیبی استفاده کنید که در آن کاربر برنامه شما را در سمت کلاینت با استفاده از کلاینت JavaScript API مجوز می‌دهد و شما یک کد مجوز یکبار مصرف ویژه را به سرور شما سرور شما این کد یکبار مصرف را مبادله می‌کند تا به خود دسترسی پیدا کند و توکن‌های تازه‌سازی را از Google دریافت کند تا سرور بتواند تماس‌های API خود را برقرار کند، این کار در زمانی که کاربر آفلاین است انجام می‌شود. این جریان کد یکبار مصرف دارای مزایای امنیتی نسبت به جریان سمت سرور خالص و ارسال نشانه های دسترسی به سرور شما است.

جریان ورود به سیستم برای به دست آوردن رمز دسترسی برای برنامه سمت سرور شما در زیر نشان داده شده است.

کدهای یکبار مصرف چندین مزیت امنیتی دارند. با کدها، گوگل توکن ها را مستقیماً بدون هیچ واسطه ای به سرور شما ارائه می دهد. اگرچه ما فاش کردن کدها را توصیه نمی کنیم، اما استفاده از آنها بدون رمز مشتری بسیار سخت است. مشتری خود را مخفی نگه دارید!

پیاده سازی جریان کد یکبار مصرف

دکمه ورود به سیستم Google یک رمز دسترسی و یک کد مجوز را ارائه می دهد. کد یک کد یکبار مصرف است که سرور شما می تواند با سرورهای Google برای یک رمز دسترسی مبادله کند.

کد نمونه زیر نحوه انجام جریان کد یکباره را نشان می دهد.

احراز هویت ورود به سیستم Google با جریان کد یکبار مصرف، شما را ملزم می‌کند:

مرحله 1: شناسه مشتری و راز مشتری ایجاد کنید

برای ایجاد شناسه مشتری و رمز سرویس گیرنده، یک پروژه کنسول API Google ایجاد کنید، یک شناسه مشتری OAuth تنظیم کنید و مبدا جاوا اسکریپت خود را ثبت کنید:

  1. به کنسول API Google بروید.

  2. از منوی کشویی پروژه، یک پروژه موجود را انتخاب کنید یا با انتخاب ایجاد یک پروژه جدید، یک پروژه جدید ایجاد کنید.

  3. در نوار کناری زیر «APIs & Services»، اعتبارنامه‌ها را انتخاب کنید، سپس روی پیکربندی صفحه رضایت کلیک کنید.

    یک آدرس ایمیل انتخاب کنید، نام محصول را مشخص کنید و ذخیره را فشار دهید.

  4. در برگه Credentials ، لیست کشویی Create credentials را انتخاب کنید و شناسه مشتری OAuth را انتخاب کنید.

  5. در قسمت Application type ، Web application را انتخاب کنید.

    مبداهایی را که برنامه شما از آنجا اجازه دسترسی به APIهای Google را دارد، به شرح زیر ثبت کنید. مبدا ترکیبی منحصر به فرد از پروتکل، نام میزبان و پورت است.

    1. در قسمت Authorized JavaScript origins ، مبدا برنامه خود را وارد کنید. می‌توانید چندین منبع را وارد کنید تا به برنامه‌تان اجازه دهید روی پروتکل‌ها، دامنه‌ها یا زیر دامنه‌های مختلف اجرا شود. شما نمی توانید از حروف عام استفاده کنید. در مثال زیر، URL دوم می تواند یک URL تولیدی باشد.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. قسمت Authorized Redirect URI نیازی به مقدار ندارد. URI های تغییر مسیر با API های جاوا اسکریپت استفاده نمی شوند.

    3. دکمه Create را فشار دهید.

  6. از کادر محاوره ای مشتری OAuth ، شناسه مشتری را کپی کنید. شناسه مشتری به برنامه شما اجازه می‌دهد به APIهای فعال Google دسترسی داشته باشد.

مرحله 2: کتابخانه پلتفرم گوگل را در صفحه خود قرار دهید

شامل اسکریپت های زیر می شود که یک تابع ناشناس را نشان می دهد که یک اسکریپت را در DOM این صفحه وب index.html درج می کند.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

مرحله 3: شی GoogleAuth را راه اندازی کنید

کتابخانه auth2 را بارگیری کنید و gapi.auth2.init() برای مقداردهی اولیه شی GoogleAuth فراخوانی کنید. شناسه مشتری خود و محدوده هایی را که می خواهید هنگام فراخوانی init() درخواست کنید، مشخص کنید.

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

مرحله 4: دکمه ورود به سیستم را به صفحه خود اضافه کنید

دکمه ورود به سیستم را به صفحه وب خود اضافه کنید و یک کنترل کننده کلیک برای فراخوانی grantOfflineAccess() برای شروع جریان یکباره کد متصل کنید.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

مرحله 5: وارد سیستم کاربر شوید

کاربر روی دکمه ورود کلیک می کند و به برنامه شما اجازه دسترسی به مجوزهایی را می دهد که درخواست کرده اید. سپس، تابع callback که در متد grantOfflineAccess().then() مشخص کرده‌اید به یک شی JSON با کد مجوز ارسال می‌شود. مثلا:

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

مرحله 6: کد مجوز را به سرور ارسال کنید

code کد یکبار مصرف شماست که سرور شما می تواند آن را با توکن دسترسی و رفرش توکن خود مبادله کند. تنها پس از ارائه یک گفتگوی مجوز برای دسترسی آفلاین به کاربر، می‌توانید یک نشانه به‌روزرسانی دریافت کنید. اگر prompt select-account در OfflineAccessOptions در مرحله 4 مشخص کرده‌اید، باید رمز تازه‌سازی را که بازیابی می‌کنید برای استفاده بعدی ذخیره کنید، زیرا مبادلات بعدی برای نشانه تازه‌سازی null برمی‌گردانند. این جریان امنیت بیشتری را نسبت به جریان استاندارد OAuth 2.0 شما فراهم می کند.

توکن های دسترسی همیشه با مبادله یک کد مجوز معتبر بازگردانده می شوند.

اسکریپت زیر یک عملکرد پاسخ به تماس را برای دکمه ورود به سیستم تعریف می کند. هنگامی که ورود موفقیت آمیز باشد، این تابع رمز دسترسی را برای استفاده در سمت سرویس گیرنده ذخیره می کند و کد یکبار مصرف را به سرور شما در همان دامنه ارسال می کند.

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

مرحله 7: کد مجوز را با یک نشانه دسترسی مبادله کنید

در سرور، کد احراز هویت را برای دسترسی و رفرش توکن ها مبادله کنید. از نشانه دسترسی برای فراخوانی APIهای Google از طرف کاربر استفاده کنید و به صورت اختیاری، رمز بازخوانی را ذخیره کنید تا زمانی که نشانه دسترسی منقضی شود، یک نشانه دسترسی جدید به دست آورید.

اگر درخواست دسترسی به نمایه را داشته باشید، یک رمز شناسایی نیز دریافت می‌کنید که حاوی اطلاعات اولیه نمایه کاربر است.

مثلا:

جاوا
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
پایتون
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']