สร้าง | การพึ่งพาอาศัยกัน |
---|---|
การใช้งาน JSON Web Tokens
สิ่งนี้ได้รับการพัฒนากับ draft-ietf-oauth-json-web-token-08
มันใช้ node-jws
$ npm ติดตั้ง jsonwebtoken
จาก v8 ถึง v9
จาก v7 ถึง v8
(อะซิงโครนัส) หากมีการระบุการโทรกลับ การโทรกลับจะถูกเรียกด้วย err
หรือ JWT
(ซิงโครนัส) ส่งกลับ JsonWebToken เป็นสตริง
payload
อาจเป็นอ็อบเจ็กต์ลิเทอรัล บัฟเฟอร์ หรือสตริงที่แสดงถึง JSON ที่ถูกต้อง
โปรด ทราบ ว่า
exp
หรือการอ้างสิทธิ์อื่นใดจะถูกตั้งค่าเฉพาะในกรณีที่เพย์โหลดเป็นวัตถุตามตัวอักษร เพย์โหลดบัฟเฟอร์หรือสตริงจะไม่ได้รับการตรวจสอบความถูกต้องของ JSON
หาก
payload
ไม่ใช่บัฟเฟอร์หรือสตริง เพย์โหลดจะถูกบังคับเป็นสตริงโดยใช้JSON.stringify
secretOrPrivateKey
คือสตริง (เข้ารหัส utf-8), บัฟเฟอร์, อ็อบเจ็กต์ หรือ KeyObject ที่ประกอบด้วยข้อมูลลับสำหรับอัลกอริทึม HMAC หรือคีย์ส่วนตัวที่เข้ารหัส PEM สำหรับ RSA และ ECDSA ในกรณีของคีย์ส่วนตัวที่มีข้อความรหัสผ่าน สามารถใช้ออบเจ็กต์ { key, passphrase }
ได้ (ขึ้นอยู่กับเอกสารการเข้ารหัส) ในกรณีนี้ ต้องแน่ใจว่าคุณผ่านตัวเลือก algorithm
เมื่อลงนามด้วยอัลกอริธึม RSA ความยาวโมดูลัสขั้นต่ำคือ 2048 ยกเว้นเมื่อตั้งค่าตัวเลือก AllowInsecureKeySizes เป็นจริง คีย์ส่วนตัวที่มีขนาดต่ำกว่านี้จะถูกปฏิเสธโดยมีข้อผิดพลาด
options
:
algorithm
(ค่าเริ่มต้น: HS256
)
expiresIn
: แสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/ms
เช่น
60
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
notBefore
: แสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/ms
เช่น
60
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
audience
issuer
jwtid
subject
noTimestamp
header
keyid
mutatePayload
: หากเป็นจริง ฟังก์ชันเครื่องหมายจะแก้ไขวัตถุเพย์โหลดโดยตรง สิ่งนี้มีประโยชน์หากคุณต้องการการอ้างอิงดิบไปยังเพย์โหลดหลังจากการอ้างสิทธิ์ได้ถูกนำไปใช้กับเพย์โหลดแล้ว แต่ก่อนที่จะถูกเข้ารหัสเป็นโทเค็น
allowInsecureKeySizes
: ถ้าเป็นจริง อนุญาตให้ใช้คีย์ส่วนตัวที่มีโมดูลัสต่ำกว่า 2048 เพื่อใช้สำหรับ RSA
allowInvalidAsymmetricKeyTypes
: หากเป็นจริง อนุญาตให้ใช้คีย์แบบอสมมาตรซึ่งไม่ตรงกับอัลกอริทึมที่ระบุ ตัวเลือกนี้มีไว้สำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น และควรหลีกเลี่ยง
ไม่มีค่าเริ่มต้นสำหรับ
expiresIn
,notBefore
,audience
,subject
,issuer
การอ้างสิทธิ์เหล่านี้สามารถระบุไว้ในเพย์โหลดได้โดยตรงด้วยexp
,nbf
,aud
,sub
และiss
ตามลำดับ แต่คุณ ไม่สามารถ รวมไว้ในทั้งสองแห่งได้
โปรดจำไว้ว่า exp
, nbf
และ iat
คือ NumericDate ดูการหมดอายุของโทเค็นที่เกี่ยวข้อง (การอ้างสิทธิ์ exp)
ส่วนหัวสามารถปรับแต่งได้ผ่านทางวัตถุ options.header
jwts ที่สร้างขึ้นจะรวมการอ้างสิทธิ์ iat
(ออกที่) ตามค่าเริ่มต้น เว้นแต่จะระบุ noTimestamp
หากใส่ iat
ลงในเพย์โหลด มันจะถูกใช้แทนการประทับเวลาจริงสำหรับการคำนวณสิ่งอื่นๆ เช่น exp
ที่กำหนดช่วงเวลาใน options.expiresIn
เครื่องหมายซิงโครนัสพร้อมค่าเริ่มต้น (HMAC SHA256)
var jwt = need('jsonwebtoken');var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
สัญญาณซิงโครนัสกับ RSA SHA256
// ลงนามด้วย RSA SHA256var privateKey = fs.readFileSync('private.key');var token = jwt.sign({ foo: 'bar' }, privateKey, { อัลกอริทึม: 'RS256' });
ลงชื่อแบบอะซิงโครนัส
jwt.sign ({ foo: 'bar' }, privateKey, { อัลกอริทึม: 'RS256' }, ฟังก์ชั่น (ผิดพลาด, โทเค็น) { console.log(โทเค็น);});
ย้อนหลัง jwt 30 วินาที
var old_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1,000) - 30 }, 'shhhhh');
มาตรฐานสำหรับ JWT กำหนดการเรียกร้อง exp
สำหรับการหมดอายุ การหมดอายุจะแสดงเป็น NumericDate :
ค่าตัวเลข JSON ที่แสดงจำนวนวินาทีตั้งแต่ 1970-01-01T00:00:00Z UTC จนถึงวันที่/เวลา UTC ที่ระบุ โดยไม่สนใจวินาทีกระโดด ซึ่งเทียบเท่ากับคำจำกัดความ IEEE Std 1003.1, 2013 Edition [POSIX.1] "วินาทีนับตั้งแต่ยุค" ซึ่งในแต่ละวันคิดเป็น 86400 วินาทีพอดี ยกเว้นค่าที่ไม่ใช่จำนวนเต็มที่สามารถแสดงได้ ดู RFC 3339 [RFC3339] สำหรับรายละเอียดเกี่ยวกับวันที่/เวลาโดยทั่วไปและโดยเฉพาะ UTC
ซึ่งหมายความว่าช่อง exp
ควรมีจำนวนวินาทีนับตั้งแต่ยุคนั้น
การลงนามโทเค็นโดยมีเวลาหมดอายุ 1 ชั่วโมง:
jwt.sign({ ประสบการณ์: Math.floor(Date.now() / 1000) + (60 * 60), ข้อมูล: 'foobar'}, 'ความลับ');
อีกวิธีในการสร้างโทเค็นเช่นนี้ด้วยไลบรารีนี้คือ:
jwt.sign({ data: 'foobar'}, 'secret', {หมดอายุIn: 60 * 60 });//หรือดีกว่านั้น:jwt.sign({ ข้อมูล: 'foobar'}, 'ความลับ', { หมดอายุใน: '1h' });
(อะซิงโครนัส) หากมีการระบุการโทรกลับ ฟังก์ชันจะดำเนินการแบบอะซิงโครนัส การโทรกลับจะถูกเรียกพร้อมกับเพย์โหลดที่ถอดรหัสแล้ว หากลายเซ็นถูกต้องและการหมดอายุ ผู้ชม หรือผู้ออกที่เป็นทางเลือกนั้นถูกต้อง ถ้าไม่เช่นนั้นจะถูกเรียกพร้อมกับข้อผิดพลาด
(ซิงโครนัส) หากไม่มีการเรียกกลับ ฟังก์ชันจะทำหน้าที่พร้อมกัน ส่งคืนเพย์โหลดที่ถอดรหัสหากลายเซ็นถูกต้องและการหมดอายุ ผู้ชม หรือผู้ออกที่เป็นตัวเลือกนั้นถูกต้อง ถ้าไม่เช่นนั้นจะเกิดข้อผิดพลาด
คำเตือน: เมื่อโทเค็นมาจากแหล่งที่ไม่น่าเชื่อถือ (เช่น อินพุตของผู้ใช้หรือคำขอจากภายนอก) เพย์โหลดที่ถอดรหัสที่ส่งคืนควรได้รับการปฏิบัติเหมือนกับอินพุตของผู้ใช้อื่น โปรดตรวจสอบให้แน่ใจว่าได้ฆ่าเชื้อและทำงานกับคุณสมบัติที่คาดหวังเท่านั้น
token
คือสตริง JsonWebToken
secretOrPublicKey
คือสตริง (เข้ารหัส utf-8) บัฟเฟอร์ หรือ KeyObject ที่ประกอบด้วยข้อมูลลับสำหรับอัลกอริทึม HMAC หรือคีย์สาธารณะที่เข้ารหัส PEM สำหรับ RSA และ ECDSA ถ้า jwt.verify
เรียกว่าอะซิงโครนัส secretOrPublicKey
อาจเป็นฟังก์ชันที่ควรดึงข้อมูลลับหรือพับลิกคีย์ ดูตัวอย่างโดยละเอียดด้านล่าง
ตามที่กล่าวไว้ในความคิดเห็นนี้มีไลบรารีอื่น ๆ ที่คาดหวังความลับที่เข้ารหัส base64 (ไบต์สุ่มเข้ารหัสโดยใช้ base64) หากเป็นกรณีของคุณคุณสามารถส่งผ่าน Buffer.from(secret, 'base64')
โดยการทำเช่นนี้ความลับจะถูกถอดรหัส การใช้ base64 และการตรวจสอบโทเค็นจะใช้ไบต์สุ่มดั้งเดิม
options
algorithms
: รายการสตริงที่มีชื่อของอัลกอริธึมที่อนุญาต ตัวอย่างเช่น ["HS256", "HS384"]
หากไม่ได้ระบุค่าเริ่มต้นจะถูกใช้ตามประเภทของคีย์ที่ให้ไว้
ความลับ - ['HS256', 'HS384', 'HS512']
อาร์เอสเอ - ['RS256', 'RS384', 'RS512']
อีซี - ['ES256', 'ES384', 'ES512']
ค่าเริ่มต้น - ['RS256', 'RS384', 'RS512']
audience
: หากคุณต้องการตรวจสอบผู้ชม ( aud
) ให้ระบุค่าที่นี่ ผู้ชมสามารถตรวจสอบกับสตริง นิพจน์ทั่วไป หรือรายการสตริงและ/หรือนิพจน์ทั่วไปได้
เช่น
"urn:foo"
,/urn:f[o]{2}/
,[/urn:f[o]{2}/, "urn:bar"]
complete
: ส่งคืนออบเจ็กต์ที่มีการถอดรหัส { payload, header, signature }
แทนที่จะเป็นเพียงเนื้อหาปกติของเพย์โหลด
issuer
(ไม่บังคับ): สตริงหรืออาร์เรย์ของสตริงที่มีค่าที่ถูกต้องสำหรับฟิลด์ iss
jwtid
(เป็นทางเลือก): หากคุณต้องการตรวจสอบ JWT ID ( jti
) ให้ระบุค่าสตริงที่นี่
ignoreExpiration
: หาก true
อย่าตรวจสอบการหมดอายุของโทเค็น
ignoreNotBefore
...
subject
: หากคุณต้องการตรวจสอบ subject ( sub
) ให้ระบุค่าที่นี่
clockTolerance
: จำนวนวินาทีที่ต้องยอมรับเมื่อตรวจสอบการอ้างสิทธิ์ nbf
และ exp
เพื่อจัดการกับความแตกต่างของนาฬิกาเล็กน้อยระหว่างเซิร์ฟเวอร์ต่างๆ
maxAge
: อายุสูงสุดที่อนุญาตสำหรับโทเค็นที่ยังคงใช้งานได้ จะแสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/ms
เช่น
1000
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
clockTimestamp
: เวลาเป็นวินาทีที่ควรใช้เป็นเวลาปัจจุบันสำหรับการเปรียบเทียบที่จำเป็นทั้งหมด
nonce
: หากคุณต้องการตรวจสอบการอ้างสิทธิ์ nonce
ให้ระบุค่าสตริงที่นี่ มันถูกใช้กับ Open ID สำหรับโทเค็น ID (บันทึกการใช้งาน Open ID)
allowInvalidAsymmetricKeyTypes
: หากเป็นจริง อนุญาตให้ใช้คีย์แบบอสมมาตรซึ่งไม่ตรงกับอัลกอริทึมที่ระบุ ตัวเลือกนี้มีไว้สำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น และควรหลีกเลี่ยง
// ตรวจสอบโทเค็นแบบสมมาตร - synchronousvar dededed = jwt.verify(token, 'shhhhh');console.log(decoded.foo) // bar// ตรวจสอบโทเค็น symmetricjwt.verify(token, 'shhhhh', function(err , ถอดรหัสแล้ว) { console.log (decoded.foo) // bar}); // โทเค็นไม่ถูกต้อง - synchronoustry { var ถอดรหัส = jwt.verify (โทเค็น 'ความลับผิด');} จับ (ผิดพลาด) { // err}// tokenjwt.verify ไม่ถูกต้อง (โทเค็น 'ความลับผิด' ฟังก์ชั่น (ผิดพลาด ถอดรหัสแล้ว) { // ผิดพลาด // ถอดรหัสไม่ได้กำหนด});// ตรวจสอบโทเค็น asymmetricvar cert = fs.readFileSync('public.pem'); // รับกุญแจสาธารณะ jwt.verify (โทเค็น, ใบรับรอง, ฟังก์ชั่น (ผิดพลาด, ถอดรหัส) { console.log(decoded.foo) // bar});// ตรวจสอบ Audiencevar cert = fs.readFileSync('public.pem'); // รับกุญแจสาธารณะjwt.verify(โทเค็น, ใบรับรอง, { ผู้ชม: 'urn:foo' }, ฟังก์ชั่น (ผิดพลาด, ถอดรหัส) { // หากผู้ชมไม่ตรงกัน ข้อผิดพลาด == ผู้ชมไม่ถูกต้อง});// ตรวจสอบใบรับรองผู้ออก = fs.readFileSync('public.pem'); // รับคีย์สาธารณะjwt.verify(token, cert, { viewer: 'urn:foo', ผู้ออก: 'urn:issuer' }, function(err, decoded) { // หากผู้ออกไม่ตรงกัน err == ผู้ออกที่ไม่ถูกต้อง});// ตรวจสอบ jwt idvar cert = fs.readFileSync('public.pem'); // รับคีย์สาธารณะjwt.verify(token, cert, { viewer: 'urn:foo', ผู้ออก: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) { // หาก jwt id ไม่ตรงกัน ข้อผิดพลาด == jwt id ไม่ถูกต้อง});// ตรวจสอบ subjectvar cert = fs.readFileSync('public.pem'); // รับคีย์สาธารณะjwt.verify(token, cert, { viewer: 'urn:foo', ผู้ออก: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) { // หากหัวเรื่องไม่ตรงกัน ข้อผิดพลาด == หัวเรื่องไม่ถูกต้อง});// alg mismatchvar cert = fs.readFileSync('public.pem'); // รับคีย์สาธารณะjwt.verify(โทเค็น, ใบรับรอง, { อัลกอริธึม: ['RS256'] }, ฟังก์ชัน (ผิดพลาด, เพย์โหลด) { // ถ้าโทเค็น alg != RS256, err == ลายเซ็นไม่ถูกต้อง});// ตรวจสอบโดยใช้ getKey callback// ตัวอย่างใช้ https://github.com/auth0/node-jwks-rsa เป็นวิธีดึงข้อมูลคีย์ var jwksClient = ต้องการ ('jwks-rsa'); var client = jwksClient ({ jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'});ฟังก์ชั่นgetKey(ส่วนหัว, โทรกลับ){ client.getSigningKey (header.kid, ฟังก์ชั่น (ผิดพลาด, คีย์) {var signingKey = key.publicKey || key.rsaPublicKey; โทรกลับ (null, signingKey); });}jwt.verify(token, getKey, options, function(err, deded) { console.log(decoded.foo) // bar});
(ซิงโครนัส) ส่งกลับเพย์โหลดที่ถอดรหัสโดยไม่ตรวจสอบว่าลายเซ็นถูกต้องหรือไม่
คำเตือน: สิ่งนี้จะ ไม่ ตรวจสอบว่าลายเซ็นนั้นถูกต้องหรือไม่ คุณ ไม่ ควรใช้สิ่งนี้กับข้อความที่ไม่น่าเชื่อถือ คุณน่าจะต้องการใช้
jwt.verify
แทน
คำเตือน: เมื่อโทเค็นมาจากแหล่งที่ไม่น่าเชื่อถือ (เช่น อินพุตของผู้ใช้หรือคำขอจากภายนอก) เพย์โหลดที่ถอดรหัสที่ส่งคืนควรได้รับการปฏิบัติเหมือนกับอินพุตของผู้ใช้อื่น โปรดตรวจสอบให้แน่ใจว่าได้ฆ่าเชื้อและทำงานกับคุณสมบัติที่คาดหวังเท่านั้น
token
คือสตริง JsonWebToken
options
:
json
: บังคับ JSON.parse บนเพย์โหลดแม้ว่าส่วนหัวจะไม่มี "typ":"JWT"
complete
: ส่งคืนออบเจ็กต์พร้อมเพย์โหลดและส่วนหัวที่ถอดรหัสแล้ว
ตัวอย่าง
// รับเพย์โหลดที่ถอดรหัสโดยไม่สนใจลายเซ็น ไม่จำเป็นต้องใช้ SecretOrPrivateKeyvar deded = jwt.decode(token);// รับเพย์โหลดที่ถอดรหัสและส่วนหัวที่ถอดรหัส = jwt.decode(token, {complete: true});console.log(decoded. ส่วนหัว);console.log(decoded.payload)
ข้อผิดพลาดที่อาจเกิดขึ้นระหว่างการตรวจสอบ ข้อผิดพลาดคืออาร์กิวเมนต์แรกของการโทรกลับเพื่อยืนยัน
เกิดข้อผิดพลาดหากโทเค็นหมดอายุ
วัตถุข้อผิดพลาด:
ชื่อ: 'TokenExpiredError'
ข้อความ: 'jwt หมดอายุแล้ว'
หมดอายุเมื่อ: [ExpDate]
jwt.verify (โทเค็น, 'shhhhh', ฟังก์ชั่น (ผิดพลาด, ถอดรหัสแล้ว) { ถ้า (ผิดพลาด) {/* err = { ชื่อ: 'TokenExpiredError', ข้อความ: 'jwt หมดอายุแล้ว', หมดอายุเมื่อ: 1408621000 } */ -
วัตถุข้อผิดพลาด:
ชื่อ: 'JsonWebTokenError'
ข้อความ:
'โทเค็นไม่ถูกต้อง' - ไม่สามารถแยกวิเคราะห์ส่วนหัวหรือเพย์โหลดได้
'jwt มีรูปแบบไม่ถูกต้อง' - โทเค็นไม่มีสามองค์ประกอบ (คั่นด้วย .
)
'ต้องมีลายเซ็น jwt'
'ลายเซ็นไม่ถูกต้อง'
'ผู้ชม jwt ไม่ถูกต้อง คาดหวัง: [OPTIONS ผู้ชม]'
'ผู้ออก jwt ไม่ถูกต้อง คาดว่า: [ผู้ออกตัวเลือก]'
'รหัส jwt ไม่ถูกต้อง' คาดหวัง: [OPTIONS JWT ID]'
'หัวข้อ jwt ไม่ถูกต้อง คาดหวัง: [OPTIONS SUBJECT]'
jwt.verify (โทเค็น, 'shhhhh', ฟังก์ชั่น (ผิดพลาด, ถอดรหัสแล้ว) { ถ้า (ผิดพลาด) {/* err = { ชื่อ: 'JsonWebTokenError', ข้อความ: 'jwt มีรูปแบบไม่ถูกต้อง' } */ -
โยนทิ้งหากเวลาปัจจุบันอยู่ก่อนการอ้างสิทธิ์ nbf
วัตถุข้อผิดพลาด:
ชื่อ: 'NotBeforeError'
ข้อความ: 'jwt ไม่ได้ใช้งานอยู่'
วันที่: 2018-10-04T16:10:44.000Z
jwt.verify (โทเค็น, 'shhhhh', ฟังก์ชั่น (ผิดพลาด, ถอดรหัสแล้ว) { if (err) {/* err = { ชื่อ: 'NotBeforeError', ข้อความ: 'jwt not active', วันที่: 2018-10-04T16:10:44.000Z } */ -
อาร์เรย์ของอัลกอริธึมที่รองรับ ปัจจุบันรองรับอัลกอริธึมต่อไปนี้
ค่าพารามิเตอร์ alg | ลายเซ็นดิจิทัลหรืออัลกอริทึม MAC |
---|---|
HS256 | HMAC ใช้อัลกอริทึมแฮช SHA-256 |
HS384 | HMAC ที่ใช้อัลกอริธึมแฮช SHA-384 |
HS512 | HMAC ที่ใช้อัลกอริธึมแฮช SHA-512 |
RS256 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริธึมแฮช SHA-256 |
RS384 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริทึมแฮช SHA-384 |
RS512 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริทึมแฮช SHA-512 |
PS256 | RSASSA-PSS ใช้อัลกอริธึมแฮช SHA-256 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
พีเอส384 | RSASSA-PSS โดยใช้อัลกอริธึมแฮช SHA-384 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
PS512 | RSASSA-PSS โดยใช้อัลกอริธึมแฮช SHA-512 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
อีเอส256 | ECDSA ใช้เส้นโค้ง P-256 และอัลกอริธึมแฮช SHA-256 |
อีเอส384 | ECDSA ใช้เส้นโค้ง P-384 และอัลกอริธึมแฮช SHA-384 |
ES512 | ECDSA ใช้เส้นโค้ง P-521 และอัลกอริธึมแฮช SHA-512 |
ไม่มี | ไม่มีลายเซ็นดิจิทัลหรือค่า MAC รวมอยู่ด้วย |
ก่อนอื่น เราขอแนะนำให้คุณคิดอย่างรอบคอบว่าการรีเฟรช JWT อัตโนมัติจะไม่ทำให้เกิดช่องโหว่ใดๆ ในระบบของคุณหรือไม่
เราไม่สบายใจที่จะรวมสิ่งนี้ไว้เป็นส่วนหนึ่งของห้องสมุด อย่างไรก็ตาม คุณสามารถดูตัวอย่างนี้เพื่อแสดงให้เห็นว่าจะบรรลุผลสำเร็จได้อย่างไร นอกเหนือจากตัวอย่างนั้น ยังมีปัญหาและการขอดึงเพื่อรับความรู้เพิ่มเติมเกี่ยวกับหัวข้อนี้
ไม่ได้ตรวจสอบสายใบรับรอง X.509
หากคุณพบจุดบกพร่องหรือหากคุณมีคำขอคุณลักษณะ โปรดรายงานในส่วนปัญหาของพื้นที่เก็บข้อมูลนี้ โปรดอย่ารายงานช่องโหว่ด้านความปลอดภัยในตัวติดตามปัญหา GitHub สาธารณะ โปรแกรมการเปิดเผยข้อมูลอย่างมีความรับผิดชอบจะให้รายละเอียดขั้นตอนในการเปิดเผยประเด็นด้านความปลอดภัย
รับรองความถูกต้อง0
โครงการนี้ได้รับอนุญาตภายใต้ใบอนุญาต MIT ดูไฟล์ใบอนุญาตสำหรับข้อมูลเพิ่มเติม