การอัปเดตบางส่วนที่อธิบายไว้ในบทความนี้ได้อธิบายไว้ในเซสชัน Google I/O การลงชื่อเข้าใช้ที่ปลอดภัยและราบรื่น: การทำให้ผู้ใช้มีส่วนร่วมอย่างต่อเนื่อง:
Chrome 57
Chrome 57 นำเสนอการเปลี่ยนแปลงที่สำคัญนี้ใน API การจัดการข้อมูลเข้าสู่ระบบ
ข้อมูลเข้าสู่ระบบสามารถแชร์จากโดเมนย่อยอื่นได้
ตอนนี้ Chrome เรียกข้อมูลเข้าสู่ระบบที่จัดเก็บไว้ในโดเมนย่อยอื่นได้โดยใช้ Credential Management API แล้ว
ตัวอย่างเช่น หากเก็บรหัสผ่านไว้ในlogin.example.com
สคริปต์ใน www.example.com
จะแสดงรหัสผ่านดังกล่าวเป็นหนึ่งในรายการบัญชีในกล่องโต้ตอบตัวเลือกบัญชีได้
คุณต้องจัดเก็บรหัสผ่านไว้อย่างชัดแจ้งโดยใช้ navigator.credentials.store()
เพื่อที่ว่าเมื่อผู้ใช้เลือกข้อมูลเข้าสู่ระบบโดยแตะกล่องโต้ตอบ ระบบจะส่งรหัสผ่านและคัดลอกไปยังต้นทางปัจจุบัน
เมื่อจัดเก็บแล้ว รหัสผ่านจะแสดงเป็นข้อมูลเข้าสู่ระบบใน www.example.com
ต้นทางเดียวกันเป็นต้นไป
ในภาพหน้าจอต่อไปนี้ m.aliexpress.com
จะเห็นข้อมูลเข้าสู่ระบบที่จัดเก็บไว้ใน login.aliexpress.com
และให้ผู้ใช้เลือกได้
![ตัวเลือกบัญชีผู้ใช้ที่แสดงรายละเอียดการเข้าสู่ระบบโดเมนย่อยที่เลือก](https://developer.chrome.com/static/blog/credential-management-updates/image/account-chooser-showing-s-369ff3f4bb61e.png?authuser=6&hl=th)
Chrome 60
Chrome 60 ทำให้เกิดการเปลี่ยนแปลงที่สำคัญหลายอย่างใน API การจัดการข้อมูลเข้าสู่ระบบ ดังนี้
เนื่องจากไม่จำเป็นต้องมีฟังก์ชัน
fetch()
ที่กำหนดเองในการดึงข้อมูลรหัสผ่านอีกต่อไป เราจะเลิกใช้งานฟังก์ชันดังกล่าวเร็วๆ นี้navigator.credentials.get()
ยอมรับ enummediation
แล้ว แทนแฟล็กบูลีนunmediated
requireUserMediation()
เปลี่ยนชื่อเป็นpreventSilentAccess()
เมธอดใหม่
navigator.credentials.create()
สร้างออบเจ็กต์ข้อมูลเข้าสู่ระบบแบบไม่พร้อมกัน
การตรวจหาฟีเจอร์ต้องได้รับการดำเนินการ
หากต้องการดูว่ามี Credential Management API สำหรับการเข้าถึงข้อมูลเข้าสู่ระบบแบบรหัสผ่านและแบบรวมศูนย์หรือไม่ ให้ตรวจสอบว่ามี window.PasswordCredential
หรือ window.FederatedCredential
หรือไม่
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
ออบเจ็กต์ PasswordCredential
รายการมีรหัสผ่านแล้ว
Credential Management API ใช้แนวทางที่เข้มงวดในการจัดการรหัสผ่าน
โดยได้ปกปิดรหัสผ่านจาก JavaScript ซึ่งกำหนดให้นักพัฒนาซอฟต์แวร์ส่งออบเจ็กต์ PasswordCredential
ไปยังเซิร์ฟเวอร์ของตนโดยตรงเพื่อตรวจสอบผ่านส่วนขยายไปยัง fetch()
API
แต่วิธีนี้ทำให้เกิดข้อจำกัดหลายประการ เราได้รับความคิดเห็นว่านักพัฒนาแอปใช้ API ไม่ได้เนื่องจากสาเหตุต่อไปนี้
ซึ่งต้องส่งรหัสผ่านโดยเป็นส่วนหนึ่งของออบเจ็กต์ JSON
ซึ่งต้องส่งค่าแฮชของรหัสผ่านไปยังเซิร์ฟเวอร์ของตน
หลังจากวิเคราะห์ความปลอดภัยและทราบว่าการปกปิดรหัสผ่านจาก JavaScript ไม่ได้ช่วยป้องกันเวกเตอร์การโจมตีได้อย่างมีประสิทธิภาพอย่างที่เราคาดหวัง เราจึงตัดสินใจทำการเปลี่ยนแปลง
ตอนนี้ Credential Management API จะมีรหัสผ่านแบบ Raw ในออบเจ็กต์ข้อมูลเข้าสู่ระบบที่ส่งกลับอยู่ เพื่อให้คุณเข้าถึงรหัสผ่านแบบข้อความธรรมดาได้ คุณสามารถใช้วิธีการที่มีอยู่เพื่อส่งข้อมูลเข้าสู่ระบบไปยังเซิร์ฟเวอร์ของคุณ โดยทำดังนี้
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(passwordCred => {
if (passwordCred) {
let form = new FormData();
form.append('email', passwordCred.id);
form.append('password', passwordCred.password);
form.append('csrf_token', csrf_token);
return fetch('/signin', {
method: 'POST',
credentials: 'include',
body: form
});
} else {
// Fallback to sign-in form
}
}).then(res => {
if (res.status === 200) {
return res.json();
} else {
throw 'Auth failed';
}
}).then(profile => {
console.log('Auth succeeded', profile);
});
เราจะเลิกใช้งานการดึงข้อมูลที่กำหนดเองเร็วๆ นี้
หากต้องการตรวจสอบว่าคุณกำลังใช้ฟังก์ชัน fetch()
ที่กำหนดเองอยู่หรือไม่ ให้ตรวจสอบว่าฟังก์ชันดังกล่าวใช้ออบเจ็กต์ PasswordCredential
หรือออบเจ็กต์ FederatedCredential
เป็นค่าของพร็อพเพอร์ตี้ credentials
เช่น
fetch('/signin', {
method: 'POST',
credentials: c
})
ขอแนะนำให้ใช้ฟังก์ชัน fetch()
ปกติตามที่แสดงในตัวอย่างโค้ดก่อนหน้านี้ หรือใช้ฟังก์ชัน XMLHttpRequest
navigator.credentials.get()
ยอมรับสื่อกลาง enum แล้ว
navigator.credentials.get()
ยอมรับพร็อพเพอร์ตี้ unmediated
ที่ไม่บังคับที่มีแฟล็กบูลีนจนถึง Chrome 60 แล้ว เช่น
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
unmediated: true
}).then(c => {
// Sign-in
});
การตั้งค่า unmediated: true
ป้องกันไม่ให้เบราว์เซอร์แสดงตัวเลือกบัญชีเมื่อส่งข้อมูลเข้าสู่ระบบ
ตอนนี้ระบบขยายการแจ้งว่าไม่เหมาะสมเป็นสื่อกลางแล้ว สื่อกลางของผู้ใช้อาจเกิดขึ้นในกรณีต่อไปนี้
ผู้ใช้จะต้องเลือกบัญชีที่จะลงชื่อเข้าใช้
ผู้ใช้ต้องการลงชื่อเข้าใช้อย่างชัดแจ้ง หลังจากการโทร
navigator.credentials.requireUseMediation()
เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้สำหรับค่า mediation
มูลค่า mediation |
เปรียบเทียบกับธงบูลีน | ลักษณะการทำงาน | |
---|---|---|---|
silent |
เท่ากับ unmediated: true |
ผ่านการตรวจสอบข้อมูลเข้าสู่ระบบโดยไม่แสดงตัวเลือกบัญชี | |
optional |
เท่ากับ unmediated: false |
แสดงตัวเลือกบัญชีหากมีการเรียกใช้ preventSilentAccess() ก่อนหน้านี้ |
|
required |
ตัวเลือกใหม่ | แสดงตัวเลือกบัญชีเสมอ มีประโยชน์เมื่อคุณต้องการให้ผู้ใช้เปลี่ยนบัญชีโดยใช้กล่องโต้ตอบตัวเลือกบัญชีเนทีฟ |
ในตัวอย่างนี้ ระบบจะส่งข้อมูลเข้าสู่ระบบโดยไม่แสดงตัวเลือกบัญชีผู้ใช้ ซึ่งเทียบเท่ากับแฟล็กก่อนหน้า unmediated: true
ดังนี้
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(c => {
// Sign-in
});
requireUserMediation()
เปลี่ยนชื่อเป็น preventSilentAccess()
แล้ว
เพื่อให้สอดคล้องกับพร็อพเพอร์ตี้ mediation
ใหม่ที่เสนอในการโทร get()
เราได้เปลี่ยนชื่อเมธอด navigator.credentials.requireUserMediation()
เป็น navigator.credentials.preventSilentAccess()
วิธีการเปลี่ยนชื่อจะป้องกันไม่ให้มีการส่งข้อมูลเข้าสู่ระบบโดยไม่แสดงตัวเลือกบัญชีผู้ใช้ (บางครั้งอาจเรียกใช้โดยไม่มีสื่อกลางผู้ใช้) วิธีนี้เป็นประโยชน์เมื่อผู้ใช้ออกจากระบบเว็บไซต์หรือยกเลิกการลงทะเบียนจากเว็บไซต์หนึ่ง และไม่ต้องการลงชื่อเข้าใช้อีกครั้งโดยอัตโนมัติในการเข้าชมครั้งถัดไป
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
สร้างออบเจ็กต์ข้อมูลเข้าสู่ระบบแบบไม่พร้อมกันด้วยเมธอดใหม่ navigator.credentials.create()
ตอนนี้คุณมีตัวเลือกในการสร้างออบเจ็กต์ข้อมูลเข้าสู่ระบบแบบไม่พร้อมกันด้วยเมธอด navigator.credentials.create()
ใหม่
อ่านต่อไปเพื่อเปรียบเทียบระหว่างแนวทางการซิงค์และอะซิงโครนัส
การสร้างออบเจ็กต์ PasswordCredential
วิธีการซิงค์
let c = new PasswordCredential(form);
วิธีการทำงานแบบไม่พร้อมกัน (ใหม่)
let c = await navigator.credentials.create({
password: form
});
หรือ
let c = await navigator.credentials.create({
password: {
id: id,
password: password
}
});
การสร้างออบเจ็กต์ FederatedCredential
วิธีการซิงค์
let c = new FederatedCredential({
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
});
วิธีการทำงานแบบไม่พร้อมกัน (ใหม่)
let c = await navigator.credentials.create({
federated: {
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
}
});
คำแนะนำในการย้ายข้อมูล
หากคุณใช้งาน Credential Management API อยู่แล้ว เรามีเอกสารคำแนะนำในการย้ายข้อมูล ที่คุณสามารถทำตามเพื่ออัปเกรดเป็นเวอร์ชันใหม่