หากต้องการใช้บริการของ Google ในนามของผู้ใช้เมื่อผู้ใช้ออฟไลน์ คุณต้องใช้ขั้นตอนฝั่งเซิร์ฟเวอร์แบบผสมที่ผู้ใช้ให้สิทธิ์แอปในฝั่งไคลเอ็นต์โดยใช้ไคลเอ็นต์ JavaScript API และส่งรหัสการให้สิทธิ์แบบครั้งเดียวพิเศษไปยังเซิร์ฟเวอร์ของคุณ เซิร์ฟเวอร์ของคุณจะแลกเปลี่ยนโค้ดแบบใช้ครั้งเดียวนี้เพื่อรับการเข้าถึงและรีเฟรชโทเค็นจาก Google เพื่อให้เซิร์ฟเวอร์เรียก API ของตัวเองได้ ซึ่งทำได้ขณะที่ผู้ใช้ออฟไลน์ ขั้นตอนของโค้ดแบบใช้ครั้งเดียวนี้มีข้อดีด้านความปลอดภัยมากกว่าขั้นตอนฝั่งเซิร์ฟเวอร์เพียงอย่างเดียวและมากกว่าการส่งโทเค็นเพื่อการเข้าถึงไปยังเซิร์ฟเวอร์
ด้านล่างนี้แสดงขั้นตอนการลงชื่อเข้าใช้เพื่อรับโทเค็นเพื่อการเข้าถึงสำหรับแอปพลิเคชันฝั่งเซิร์ฟเวอร์
รหัสแบบใช้ครั้งเดียวมีข้อดีด้านความปลอดภัยหลายประการ เมื่อใช้รหัส Google จะ มอบโทเค็นไปยังเซิร์ฟเวอร์โดยตรงโดยไม่ต้องมีตัวกลาง แม้ว่าเราจะไม่แนะนำให้ใช้โค้ดที่รั่วไหล แต่ใช้งานได้ยากมากโดยไม่ต้องใช้รหัสลับไคลเอ็นต์ เก็บรหัสลับไคลเอ็นต์ไว้!
การใช้ขั้นตอนการใช้โค้ดแบบครั้งเดียว
ปุ่ม Google Sign-In จะมีทั้งโทเค็นเพื่อการเข้าถึงและรหัสการให้สิทธิ์ โค้ดดังกล่าวเป็นรหัสแบบใช้ครั้งเดียวที่เซิร์ฟเวอร์จะแลกเปลี่ยนกับเซิร์ฟเวอร์ของ Google เป็นโทเค็นเพื่อการเข้าถึงได้
โค้ดตัวอย่างต่อไปนี้แสดงวิธีการดำเนินการขั้นตอนการใช้โค้ดแบบครั้งเดียว
คุณต้องทำดังนี้เพื่อตรวจสอบสิทธิ์ Google Sign-In ด้วยรหัสแบบครั้งเดียว
ขั้นตอนที่ 1: สร้างรหัสไคลเอ็นต์และรหัสลับไคลเอ็นต์
หากต้องการสร้างรหัสไคลเอ็นต์และรหัสลับไคลเอ็นต์ ให้สร้างโปรเจ็กต์คอนโซล Google API, ตั้งค่ารหัสไคลเอ็นต์ OAuth และลงทะเบียนต้นทางของ JavaScript ดังนี้
ไปที่คอนโซล Google API
จากเมนูแบบเลื่อนลงของโปรเจ็กต์ ให้เลือกโปรเจ็กต์ที่มีอยู่หรือสร้างโปรเจ็กต์ใหม่โดยเลือกสร้างโปรเจ็กต์ใหม่
ในแถบด้านข้างใต้ "API และบริการ" ให้เลือกข้อมูลเข้าสู่ระบบ แล้วคลิกกำหนดค่าหน้าจอคำยินยอม
เลือกอีเมล ระบุชื่อผลิตภัณฑ์ แล้วกดบันทึก
ในแท็บข้อมูลเข้าสู่ระบบ ให้เลือกรายการแบบเลื่อนลงสร้างข้อมูลเข้าสู่ระบบ แล้วเลือกรหัสไคลเอ็นต์ OAuth
ในส่วนประเภทแอปพลิเคชัน ให้เลือกเว็บแอปพลิเคชัน
ลงทะเบียนต้นทางที่แอปของคุณได้รับอนุญาตให้เข้าถึง Google APIs ดังนี้ ต้นทางเป็นการรวมโปรโตคอล ชื่อโฮสต์ และพอร์ตที่ไม่ซ้ำกัน
ในช่องต้นทาง JavaScript ที่ได้รับอนุญาต ให้ป้อนต้นทางของแอป คุณสามารถป้อนต้นทางหลายรายการเพื่อให้แอปทำงานในโปรโตคอล โดเมน หรือโดเมนย่อยที่แตกต่างกันได้ คุณไม่สามารถใช้ไวลด์การ์ด ในตัวอย่างด้านล่าง URL ที่ 2 อาจเป็น URL เวอร์ชันที่ใช้งานจริง
http://localhost:8080 https://myproductionurl.example.com
ช่อง URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตไม่จำเป็นต้องมีค่า URI การเปลี่ยนเส้นทางไม่ใช้กับ JavaScript API
กดปุ่มสร้าง
คัดลอกรหัสไคลเอ็นต์จากกล่องโต้ตอบไคลเอ็นต์ OAuth ที่ปรากฏขึ้น รหัสไคลเอ็นต์ช่วยให้แอปของคุณเข้าถึง Google API ที่เปิดใช้อยู่ได้
ขั้นตอนที่ 2: ใส่ไลบรารีแพลตฟอร์มของ Google ในหน้าเว็บ
ใส่สคริปต์ต่อไปนี้ซึ่งสาธิตฟังก์ชันที่ไม่ระบุชื่อที่แทรกสคริปต์ลงใน 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 มาตรฐาน
โทเค็นเพื่อการเข้าถึงจะส่งคืนพร้อมการแลกเปลี่ยนรหัสการให้สิทธิ์ที่ถูกต้องเสมอ
สคริปต์ต่อไปนี้จะกำหนดฟังก์ชัน Callback สำหรับปุ่มลงชื่อเข้าใช้ เมื่อลงชื่อเข้าใช้สำเร็จ ฟังก์ชันจะจัดเก็บโทเค็นเพื่อการเข้าถึงสำหรับการใช้งานฝั่งไคลเอ็นต์และส่งรหัสแบบใช้ครั้งเดียวไปยังเซิร์ฟเวอร์ของคุณในโดเมนเดียวกัน
<!-- 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: แลกเปลี่ยนรหัสการให้สิทธิ์สำหรับโทเค็นเพื่อการเข้าถึง
แลกเปลี่ยนรหัสการตรวจสอบสิทธิ์ในเซิร์ฟเวอร์เพื่อการเข้าถึงและรีเฟรชโทเค็น ใช้โทเค็นเพื่อการเข้าถึงเพื่อเรียกใช้ Google APIs ในนามของผู้ใช้ หรือจัดเก็บโทเค็นการรีเฟรชเพื่อขอโทเค็นเพื่อการเข้าถึงใหม่เมื่อโทเค็นเพื่อการเข้าถึงหมดอายุ
หากขอสิทธิ์เข้าถึงโปรไฟล์ คุณจะได้รับโทเค็นรหัสที่มีข้อมูลโปรไฟล์พื้นฐานสำหรับผู้ใช้ด้วย
เช่น
Java
// (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");
Python
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']