การอัปเดตล่าสุดของ API การจัดการข้อมูลเข้าสู่ระบบ

การอัปเดตบางส่วนที่อธิบายไว้ในบทความนี้ได้อธิบายไว้ในเซสชัน 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 และให้ผู้ใช้เลือกได้

ตัวเลือกบัญชีผู้ใช้ที่แสดงรายละเอียดการเข้าสู่ระบบโดเมนย่อยที่เลือก

Chrome 60

Chrome 60 ทำให้เกิดการเปลี่ยนแปลงที่สำคัญหลายอย่างใน API การจัดการข้อมูลเข้าสู่ระบบ ดังนี้

การตรวจหาฟีเจอร์ต้องได้รับการดำเนินการ

หากต้องการดูว่ามี 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() ยอมรับพร็อพเพอร์ตี้ 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 อยู่แล้ว เรามีเอกสารคำแนะนำในการย้ายข้อมูล ที่คุณสามารถทำตามเพื่ออัปเกรดเป็นเวอร์ชันใหม่