با یک سرور باطن احراز هویت

اگر از Google Sign-In با برنامه یا سایتی استفاده می‌کنید که با سرور پشتیبان ارتباط برقرار می‌کند، ممکن است لازم باشد کاربر وارد شده فعلی را در سرور شناسایی کنید. برای انجام این کار به صورت ایمن، پس از اینکه کاربر با موفقیت وارد سیستم شد، رمز ID کاربر را با استفاده از HTTPS به سرور خود ارسال کنید. سپس، در سرور، یکپارچگی شناسه شناسه را بررسی کنید و از اطلاعات کاربری موجود در توکن برای ایجاد یک جلسه یا ایجاد یک حساب جدید استفاده کنید.

رمز ID را به سرور خود ارسال کنید

پس از اینکه کاربر با موفقیت به سیستم وارد شد، کد شناسه کاربر را دریافت کنید:

سویفت

GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
    guard error == nil else { return }
    guard let signInResult = signInResult else { return }

    signInResult.user.refreshTokensIfNeeded { user, error in
        guard error == nil else { return }
        guard let user = user else { return }

        let idToken = user.idToken
        // Send ID token to backend (example below).
    }
}

هدف-C

[GIDSignIn.sharedInstance signInWithPresentingViewController:self
                                              completion:^(GIDSignInResult * _Nullable signInResult,
                                                           NSError * _Nullable error) {
      if (error) { return; }
      if (signInResult == nil) { return; }

      [signInResult.user refreshTokensIfNeededWithCompletion:^(GIDGoogleUser * _Nullable user,
                                                               NSError * _Nullable error) {
          if (error) { return; }
          if (user == nil) { return; }

          NSString *idToken = user.idToken;
          // Send ID token to backend (example below).
      }];
}];

سپس، رمز ID را با یک درخواست HTTPS POST به سرور خود ارسال کنید:

سویفت

func tokenSignInExample(idToken: String) {
    guard let authData = try? JSONEncoder().encode(["idToken": idToken]) else {
        return
    }
    let url = URL(string: "https://yourbackend.example.com/tokensignin")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    let task = URLSession.shared.uploadTask(with: request, from: authData) { data, response, error in
        // Handle response from your backend.
    }
    task.resume()
}

هدف-C

NSString *signinEndpoint = @"https://yourbackend.example.com/tokensignin";
NSDictionary *params = @{@"idtoken": idToken};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:signinEndpoint];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[self httpBodyForParamsDictionary:params]];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:queue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                         if (error) {
                           NSLog(@"Error: %@", error.localizedDescription);
                         } else {
                           NSLog(@"Signed in as %@", data.bytes);
                         }
                       }];

یکپارچگی شناسه رمز را بررسی کنید

پس از دریافت کد ID توسط HTTPS POST، باید یکپارچگی توکن را تأیید کنید.

برای تأیید معتبر بودن توکن، اطمینان حاصل کنید که معیارهای زیر برآورده می شوند:

  • رمز شناسه به درستی توسط گوگل امضا شده است. از کلیدهای عمومی Google (در قالب JWK یا PEM موجود است) برای تأیید امضای توکن استفاده کنید. این کلیدها به طور منظم چرخانده می شوند. هدر Cache-Control را در پاسخ بررسی کنید تا مشخص کنید چه زمانی باید دوباره آنها را بازیابی کنید.
  • مقدار aud در کد ID برابر با یکی از شناسه های مشتری برنامه شما است. این بررسی برای جلوگیری از استفاده از کدهای شناسه صادر شده برای یک برنامه مخرب برای دسترسی به داده‌های مربوط به همان کاربر در سرور پشتیبان برنامه شما ضروری است.
  • مقدار iss در کد شناسه برابر با accounts.google.com یا https://accounts.google.com است.
  • زمان انقضا ( exp ) شناسه توکن سپری نشده است.
  • اگر باید تأیید کنید که رمز شناسه یک حساب سازمانی Google Workspace یا Cloud را نشان می‌دهد، می‌توانید ادعای hd را بررسی کنید، که دامنه میزبانی کاربر را نشان می‌دهد. این باید زمانی استفاده شود که دسترسی به یک منبع را فقط به اعضای دامنه های خاص محدود می کند. عدم وجود این ادعا نشان می دهد که این حساب متعلق به دامنه میزبان گوگل نیست.

با استفاده از فیلدهای email ، email_verified و hd ، می‌توانید تعیین کنید که آیا Google میزبان آدرس ایمیل است یا خیر. در مواردی که Google معتبر است، کاربر به عنوان مالک قانونی حساب شناخته می‌شود و ممکن است از رمز عبور یا سایر روش‌های چالش صرفنظر کنید.

مواردی که گوگل معتبر است:

  • email دارای پسوند @gmail.com است، این یک حساب کاربری جیمیل است.
  • email_verified درست است و hd تنظیم شده است، این یک حساب G Suite است.

کاربران می توانند بدون استفاده از Gmail یا G Suite برای حساب های Google ثبت نام کنند. وقتی email حاوی پسوند @gmail.com نیست و hd وجود ندارد، گوگل معتبر نیست و رمز عبور یا روش‌های چالش دیگری برای تأیید کاربر توصیه می‌شود. email_verified همچنین می تواند درست باشد زیرا Google در ابتدا کاربر را هنگام ایجاد حساب Google تأیید کرد، اما مالکیت حساب ایمیل شخص ثالث ممکن است از آن زمان تغییر کرده باشد.

به جای نوشتن کد خود برای انجام این مراحل تأیید، ما قویاً توصیه می‌کنیم از کتابخانه سرویس گیرنده Google API برای پلتفرم خود یا یک کتابخانه JWT همه منظوره استفاده کنید. برای توسعه و اشکال‌زدایی، می‌توانید با نقطه پایانی اعتبارسنجی tokeninfo ما تماس بگیرید.

استفاده از Google API Client Library

استفاده از یکی از کتابخانه های Google API Client (به عنوان مثال جاوا ، Node.js ، PHP ، Python ) روش توصیه شده برای اعتبارسنجی توکن های Google ID در یک محیط تولید است.

جاوا

برای تأیید اعتبار یک نشانه شناسه در جاوا، از شی GoogleIdTokenVerifier استفاده کنید. به عنوان مثال:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  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");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

متد GoogleIdTokenVerifier.verify() امضای JWT، ادعای aud ، ادعای iss و ادعای exp را تأیید می‌کند.

اگر باید تأیید کنید که رمز شناسه یک حساب سازمانی Google Workspace یا Cloud را نشان می‌دهد، می‌توانید با بررسی نام دامنه بازگردانده شده با روش Payload.getHostedDomain() ادعای hd را تأیید کنید. دامنه ادعای email برای اطمینان از مدیریت حساب توسط یک دامنه یا سازمان کافی نیست.

Node.js

برای تأیید اعتبار یک نشانه شناسه در Node.js، از کتابخانه Google Auth برای Node.js استفاده کنید. کتابخانه را نصب کنید:

npm install google-auth-library --save
سپس تابع verifyIdToken() فراخوانی کنید. به عنوان مثال:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client();
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If the request specified a Google Workspace domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

تابع verifyIdToken امضای JWT، ادعای aud ، ادعای exp و ادعای iss را تأیید می کند.

اگر باید تأیید کنید که رمز شناسه یک حساب سازمانی Google Workspace یا Cloud را نشان می‌دهد، می‌توانید ادعای hd را بررسی کنید، که دامنه میزبانی کاربر را نشان می‌دهد. این باید زمانی استفاده شود که دسترسی به یک منبع را فقط به اعضای دامنه های خاص محدود می کند. عدم وجود این ادعا نشان می دهد که این حساب متعلق به دامنه میزبان گوگل نیست.

PHP

برای تأیید اعتبار یک نشانه شناسه در PHP، از Google API Client Library برای PHP استفاده کنید. کتابخانه را نصب کنید (مثلاً با استفاده از Composer):

composer require google/apiclient
سپس تابع verifyIdToken() فراخوانی کنید. به عنوان مثال:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If the request specified a Google Workspace domain
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

تابع verifyIdToken امضای JWT، ادعای aud ، ادعای exp و ادعای iss را تأیید می کند.

اگر باید تأیید کنید که رمز شناسه یک حساب سازمانی Google Workspace یا Cloud را نشان می‌دهد، می‌توانید ادعای hd را بررسی کنید، که دامنه میزبانی کاربر را نشان می‌دهد. این باید زمانی استفاده شود که دسترسی به یک منبع را فقط به اعضای دامنه های خاص محدود می کند. عدم وجود این ادعا نشان می دهد که این حساب متعلق به دامنه میزبان گوگل نیست.

پایتون

برای تأیید اعتبار یک نشانه ID در پایتون، از تابع verify_oauth2_token استفاده کنید. به عنوان مثال:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If the request specified a Google Workspace domain
    # if idinfo['hd'] != DOMAIN_NAME:
    #     raise ValueError('Wrong domain name.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

تابع verify_oauth2_token امضای JWT، ادعای aud و ادعای exp را تأیید می کند. همچنین باید ادعای hd (در صورت وجود) را با بررسی شیئی که verify_oauth2_token برمی گرداند تأیید کنید. اگر چندین مشتری به سرور باطن دسترسی دارند، ادعای aud را نیز به صورت دستی تأیید کنید.

تماس با نقطه پایانی tokeninfo

یک راه آسان برای تأیید اعتبار امضای رمز شناسه برای اشکال‌زدایی ، استفاده از نقطه پایانی tokeninfo است. فراخوانی این نقطه پایانی شامل یک درخواست شبکه اضافی است که بیشتر اعتبارسنجی را برای شما انجام می دهد، در حالی که شما اعتبارسنجی مناسب و استخراج محموله را در کد خود آزمایش می کنید. برای استفاده در کد تولید مناسب نیست زیرا ممکن است درخواست‌ها کاهش یابد یا در معرض خطاهای متناوب قرار گیرند.

برای تأیید اعتبار یک نشانه شناسه با استفاده از نقطه پایانی tokeninfo ، یک درخواست HTTPS POST یا GET به نقطه پایانی ارسال کنید و رمز ID خود را در پارامتر id_token ارسال کنید. به عنوان مثال، برای تأیید اعتبار رمز XYZ123، درخواست GET زیر را انجام دهید:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

اگر توکن به درستی امضا شده باشد و ادعاهای iss و exp مقادیر مورد انتظار را داشته باشند، یک پاسخ HTTP 200 دریافت خواهید کرد که در آن بدنه شامل ادعاهای رمز ID با فرمت JSON است. در اینجا یک نمونه پاسخ آمده است:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

اگر باید تأیید کنید که رمز ID نشان دهنده یک حساب Google Workspace است، می توانید ادعای hd را بررسی کنید که دامنه میزبانی کاربر را نشان می دهد. این باید زمانی استفاده شود که دسترسی به یک منبع را فقط به اعضای دامنه های خاص محدود می کند. عدم وجود این ادعا نشان می‌دهد که این حساب متعلق به دامنه میزبان Google Workspace نیست.

یک حساب کاربری یا جلسه ایجاد کنید

پس از اینکه رمز را تأیید کردید، بررسی کنید که آیا کاربر قبلاً در پایگاه داده کاربر شما قرار دارد یا خیر. اگر چنین است، یک جلسه تأیید اعتبار برای کاربر ایجاد کنید. اگر کاربر هنوز در پایگاه داده کاربر شما نیست، یک رکورد کاربری جدید از اطلاعات موجود در بار توکن شناسه ایجاد کنید و یک جلسه برای کاربر ایجاد کنید. هنگامی که کاربر تازه ایجاد شده را در برنامه خود شناسایی می کنید، می توانید از کاربر درخواست کنید که اطلاعات نمایه اضافی مورد نیاز خود را دریافت کند.

ایمن سازی حساب های کاربران خود با محافظت از حساب های متقابل

وقتی برای ورود کاربر به Google متکی هستید، به طور خودکار از تمام ویژگی‌های امنیتی و زیرساخت‌هایی که Google برای محافظت از داده‌های کاربر ایجاد کرده است، بهره‌مند می‌شوید. با این حال، در صورت بعید بودن که حساب Google کاربر به خطر بیفتد یا رویداد امنیتی مهم دیگری رخ دهد، برنامه شما نیز می‌تواند در برابر حمله آسیب‌پذیر باشد. برای محافظت بهتر از حساب‌های خود در برابر هر رویداد امنیتی مهم، از «حفاظت بین حساب‌ها» برای دریافت هشدارهای امنیتی از Google استفاده کنید. وقتی این رویدادها را دریافت می‌کنید، تغییرات مهمی را در امنیت حساب Google کاربر مشاهده می‌کنید و سپس می‌توانید برای امنیت حساب‌های خود در سرویس خود اقدام کنید.