ด้วยการมาถึงของเฟรมเวิร์กฟรอนต์เอนด์ที่มีคุณลักษณะมากมายเช่น AngularJS จึงมีการนำตรรกะมาใช้ในส่วนหน้ามากขึ้นเรื่อย ๆ เช่นการจัดการข้อมูล / การตรวจสอบความถูกต้องการรับรองความถูกต้องและอื่น ๆ Satellizer ซึ่งเป็นโมดูลการรับรองความถูกต้องโดยใช้โทเค็นที่ใช้งานง่ายสำหรับ AngularJS ช่วยลดความยุ่งยากในกระบวนการใช้กลไกการตรวจสอบสิทธิ์ใน AngularJS ไลบรารีมาพร้อมกับการสนับสนุนในตัวสำหรับ Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch และบัญชี Microsoft (Windows Live)
ในบทความนี้เราจะสร้างเว็บแอพที่เรียบง่ายคล้ายกับแอพ ที่นี่ ซึ่งช่วยให้คุณสามารถเข้าสู่ระบบและดูข้อมูลของผู้ใช้ปัจจุบัน
คำเหล่านี้เป็น 2 คำที่น่ากลัวที่คุณมักจะพบเมื่อแอปของคุณเริ่มรวมระบบผู้ใช้ อ้างอิงจาก Wikipedia:
การรับรองความถูกต้อง เป็นการยืนยันความจริงของแอตทริบิวต์ของข้อมูลชิ้นเดียว (ข้อมูล) ที่หน่วยงานอ้างว่าเป็นความจริง
การอนุญาต เป็นหน้าที่ในการระบุสิทธิ์การเข้าถึงทรัพยากรที่เกี่ยวข้องกับความปลอดภัยของข้อมูลและความปลอดภัยของคอมพิวเตอร์โดยทั่วไปและเพื่อการควบคุมการเข้าถึงโดยเฉพาะ
ในแง่ของคนธรรมดาเรามาดูตัวอย่างเว็บไซต์บล็อกที่มีบางคนทำงานอยู่ บล็อกเกอร์เขียนบทความและผู้จัดการตรวจสอบเนื้อหา แต่ละคนสามารถพิสูจน์ตัวตน (ล็อกอิน) เข้าสู่ระบบได้ แต่สิทธิ์ (การให้สิทธิ์) นั้นแตกต่างกันดังนั้นบล็อกเกอร์จึงไม่สามารถตรวจสอบเนื้อหาได้ในขณะที่ผู้จัดการสามารถทำได้
คุณสามารถสร้างระบบการพิสูจน์ตัวตนของคุณเองใน AngularJS ได้โดยทำตามบทช่วยสอนบางอย่างเช่นแบบละเอียดนี้: JSON Web Token Tutorial: ตัวอย่างใน Laravel และ AngularJS . ฉันขอแนะนำให้อ่านบทความนี้เนื่องจากอธิบาย JWT (JSON Web Token) ได้เป็นอย่างดีและแสดงวิธีง่ายๆในการใช้การตรวจสอบสิทธิ์ใน AngularJS โดยใช้ที่เก็บข้อมูลในเครื่องและตัวดักจับ HTTP โดยตรง
แล้วทำไมต้อง Satellizer? เหตุผลหลักคือมันรองรับการเข้าสู่ระบบเครือข่ายโซเชียลจำนวนหนึ่งเช่น Facebook, Twitter และอื่น ๆ ในปัจจุบันโดยเฉพาะอย่างยิ่งสำหรับเว็บไซต์ที่ใช้บนมือถือการพิมพ์ชื่อผู้ใช้และรหัสผ่านนั้นค่อนข้างยุ่งยากและผู้ใช้คาดว่าจะสามารถใช้เว็บไซต์ของคุณได้โดยมีอุปสรรคเล็กน้อย โดยใช้การเข้าสู่ระบบโซเชียล เนื่องจากการรวม SDK ของแต่ละเครือข่ายโซเชียลและการปฏิบัติตามเอกสารของพวกเขานั้นค่อนข้างซ้ำซากจึงเป็นการดีที่จะสนับสนุนการเข้าสู่ระบบโซเชียลเหล่านี้ด้วยความพยายามเพียงเล็กน้อย
นอกจากนี้ Satellizer ยังเป็นไฟล์ คล่องแคล่ว โครงการบน Github Active เป็นกุญแจสำคัญที่นี่เนื่องจาก SDK เหล่านี้มีการเปลี่ยนแปลงค่อนข้างบ่อยและคุณไม่ต้องการอ่านเอกสารของพวกเขาเป็นระยะ ๆ (ใครก็ตามที่ทำงานกับ Facebook SDK จะรู้ว่ามันน่ารำคาญแค่ไหน)
นี่คือจุดเริ่มต้นที่น่าสนใจ
เราจะสร้างเว็บแอปที่มีกลไกการเข้าสู่ระบบ / ลงทะเบียนเป็นประจำ (เช่นการใช้ชื่อผู้ใช้รหัสผ่าน) และรองรับการเข้าสู่ระบบโซเชียลด้วย เว็บแอพนี้ง่ายมากเพราะมีเพียง 3 หน้า:
สำหรับแบ็กเอนด์เราจะใช้ Python และ Flask Python และ Framework Flask ค่อนข้างแสดงออกดังนั้นฉันหวังว่าการพอร์ตโค้ดไปยังภาษา / เฟรมเวิร์กอื่นจะไม่ยากนัก แน่นอนเราจะใช้ AngularJS สำหรับส่วนหน้า และสำหรับการเข้าสู่ระบบโซเชียลเราจะรวมเข้ากับ Facebook เท่านั้นเนื่องจากเป็นเครือข่ายโซเชียลที่ได้รับความนิยมมากที่สุดในขณะนี้
เริ่มกันเลย!
นี่คือวิธีที่เราจะจัดโครงสร้างโค้ดของเรา:
- app.py - static/ - index.html - app.js - bower.json - partials/ - login.tpl.html - home.tpl.html - secret.tpl.html
รหัสส่วนหลังทั้งหมดอยู่ใน app.py . รหัสส่วนหน้าถูกใส่ไว้ในโฟลเดอร์ / แบบคงที่ โดยค่าเริ่มต้น Flask จะให้บริการเนื้อหาของคงที่ / โฟลเดอร์โดยอัตโนมัติ มุมมองบางส่วนทั้งหมดอยู่ในแบบคงที่ / บางส่วน / และจัดการโดยโมดูล ui.router
ในการเริ่มเขียนโค้ดส่วนหลังเราต้องใช้ Python 2.7. * และติดตั้งไลบรารีที่จำเป็นโดยใช้ pip คุณสามารถใช้ได้แน่นอน Virtualenv เพื่อแยกสภาพแวดล้อม Python ด้านล่างนี้คือรายชื่อโมดูล Python ที่จำเป็นสำหรับใส่ใน requirements.txt:
Flask==0.10.1 PyJWT==1.4.0 Flask-SQLAlchemy==1.0 requests==2.7.0
ในการติดตั้งการอ้างอิงทั้งหมดเหล่านี้:
pip install -r requirements.txt
ใน app.py เรามีรหัสเริ่มต้นสำหรับ bootstrap Flask (คำสั่งนำเข้าถูกละไว้เพื่อความกะทัดรัด):
app = Flask(__name__) @app.route('/') def index(): return flask.redirect('/static/index.html') if __name__ == '__main__': app.run(debug=True)
ต่อไปเรา ในนั้น bower และติดตั้ง AngularJS และ ui.router:
bower init # here you will need to answer some question. when in doubt, just hit enter :) bower install angular angular-ui-router --save # install and save these dependencies into bower.json
เมื่อติดตั้งไลบรารีเหล่านี้แล้วเราจำเป็นต้องรวม AngularJS และ ui-router เข้าด้วยกัน index.html และสร้างเส้นทางสำหรับ 3 เพจ: บ้านล็อกอินและความลับ
Home Login Secret
ด้านล่างนี้คือรหัสที่เราต้องการใน main.js เพื่อกำหนดค่าการกำหนดเส้นทาง:
var app = angular.module('DemoApp', ['ui.router']); app.config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('home', { url: '/home', templateUrl: 'partials/home.tpl.html' }) .state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', }) .state('login', { url: '/login', templateUrl: 'partials/login.tpl.html' }); $urlRouterProvider.otherwise('/home'); });
ณ จุดนี้หากคุณรันเซิร์ฟเวอร์ python app.py คุณควรมีอินเทอร์เฟซพื้นฐานนี้ที่ http: // localhost: 5000
ลิงก์หน้าแรกการเข้าสู่ระบบและความลับควรใช้งานได้ ณ จุดนี้และแสดงเนื้อหาของเทมเพลตที่เกี่ยวข้อง
ขอแสดงความยินดีคุณเพิ่งตั้งโครงกระดูกเสร็จแล้ว! หากคุณพบข้อผิดพลาดใด ๆ โปรดตรวจสอบไฟล์ รหัสบน GitHub
ในตอนท้ายของขั้นตอนนี้คุณจะมีเว็บแอปที่คุณสามารถลงทะเบียน / เข้าสู่ระบบโดยใช้อีเมลและรหัสผ่าน
ขั้นตอนแรกคือการกำหนดค่าแบ็กเอนด์ เราต้องการโมเดลผู้ใช้และวิธีสร้างโทเค็น JWT สำหรับผู้ใช้ที่กำหนด รูปแบบผู้ใช้ที่แสดงด้านล่างนี้ง่ายมากและไม่ได้ทำการตรวจสอบขั้นพื้นฐานใด ๆ เช่นฟิลด์ if อีเมล์ มี“ @” หรือฟิลด์ if รหัสผ่าน มีอักขระอย่างน้อย 6 ตัวเป็นต้น
class User(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100), nullable=False) password = db.Column(db.String(100)) def token(self): payload = { 'sub': self.id, 'iat': datetime.utcnow(), 'exp': datetime.utcnow() + timedelta(days=14) } token = jwt.encode(payload, app.config['TOKEN_SECRET']) return token.decode('unicode_escape')
เราใช้โมดูล jwt ใน python เพื่อสร้างส่วน payload ใน JWT ส่วน iat และ exp สอดคล้องกับการประทับเวลาที่โทเค็นถูกสร้างขึ้นและหมดอายุ ในรหัสนี้โทเค็นจะหมดอายุใน 2 สัปดาห์
หลังจากสร้างโมเดลผู้ใช้แล้วเราสามารถเพิ่มปลายทาง 'เข้าสู่ระบบ' และ 'ลงทะเบียน' ได้ รหัสของทั้งคู่ค่อนข้างคล้ายกันดังนั้นที่นี่ฉันจะแสดงส่วน 'register' โปรดทราบว่าโดยค่าเริ่มต้น Satellizer จะเรียกจุดสิ้นสุด / auth / เข้าสู่ระบบ และ / auth / signup สำหรับ 'เข้าสู่ระบบ' และ 'ลงทะเบียน' ตามลำดับ
@app.route('/auth/signup', methods=['POST']) def signup(): data = request.json email = data['email'] password = data['password'] user = User(email=email, password=password) db.session.add(user) db.session.commit() return jsonify(token=user.token())
มาตรวจสอบจุดสิ้นสุดโดยใช้ curl ก่อน:
curl localhost:5000/auth/signup -H 'Content-Type: application/json' -X POST -d '{'email':' [email protected] ','password':'xyz'}'
ผลลัพธ์ควรมีลักษณะดังนี้:
{ 'token': 'very long string….' }
ตอนนี้ส่วนหลังพร้อมแล้วมาโจมตีส่วนหน้ากัน! ขั้นแรกเราต้องติดตั้ง satellizer และเพิ่มเป็นการอ้างอิงใน main.js:
bower install satellizer --save
เพิ่ม satellizer เป็นการพึ่งพา:
var app = angular.module('DemoApp', ['ui.router', 'satellizer']);
การเข้าสู่ระบบและลงทะเบียนใน satellizer นั้นค่อนข้างง่ายเมื่อเทียบกับการตั้งค่าทั้งหมดจนถึงตอนนี้:
$scope.signUp = function () { $auth .signup({email: $scope.email, password: $scope.password}) .then(function (response) { // set the token received from server $auth.setToken(response); // go to secret page $state.go('secret'); }) .catch(function (response) { console.log('error response', response); }) };
หากคุณมีปัญหาในการตั้งค่ารหัสคุณสามารถดูที่ไฟล์ รหัสบน GitHub .
ใช่ถูกต้อง! จนถึงขณะนี้ทุกคนสามารถไปที่หน้าลับโดยไม่ต้องเข้าสู่ระบบ
ถึงเวลาเพิ่ม interceptor ใน AngularJS เพื่อให้แน่ใจว่าหากมีคนไปที่หน้าลับและหากผู้ใช้รายนี้ไม่ได้เข้าสู่ระบบระบบจะเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบ
อันดับแรกเราควรเพิ่มค่าสถานะ requiredLogin เพื่อแยกหน้าลับออกจากหน้าอื่น ๆ
.state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', controller: 'SecretCtrl', data: {requiredLogin: true} })
ส่วน 'data' จะถูกใช้ในเหตุการณ์ $ stateChangeStart ซึ่งจะเริ่มทำงานทุกครั้งที่มีการเปลี่ยนแปลงเส้นทาง:
app.run(function ($rootScope, $state, $auth) { $rootScope.$on('$stateChangeStart', function (event, toState) { var requiredLogin = false; // check if this state need login if (toState.data && toState.data.requiredLogin) requiredLogin = true; // if yes and if this user is not logged in, redirect him to login page if (requiredLogin && !$auth.isAuthenticated()) { event.preventDefault(); $state.go('login'); } }); });
ตอนนี้ผู้ใช้ไม่สามารถไปที่หน้าลับได้โดยตรงโดยไม่ต้องเข้าสู่ระบบไชโย!
ตามปกติรหัสของขั้นตอนนี้สามารถพบได้ ที่นี่ .
ในขณะนี้ไม่มีอะไรเป็นความลับในหน้าลับ มาใส่ความเป็นส่วนตัวกัน
ขั้นตอนนี้เริ่มต้นด้วยการสร้างจุดสิ้นสุดในส่วนหลังซึ่งสามารถเข้าถึงได้สำหรับผู้ใช้ที่พิสูจน์ตัวตนแล้วเท่านั้นเช่นการมีโทเค็นที่ถูกต้อง จุดสิ้นสุด / ผู้ใช้ ด้านล่างส่งคืนไฟล์ user_id และ อีเมล์ ของผู้ใช้ที่ตรงกับโทเค็น
@app.route('/user') def user_info(): # the token is put in the Authorization header if not request.headers.get('Authorization'): return jsonify(error='Authorization header missing'), 401 # this header looks like this: “Authorization: Bearer {token}” token = request.headers.get('Authorization').split()[1] try: payload = jwt.decode(token, app.config['TOKEN_SECRET']) except DecodeError: return jsonify(error='Invalid token'), 401 except ExpiredSignature: return jsonify(error='Expired token'), 401 else: user_id = payload['sub'] user = User.query.filter_by(id=user_id).first() if user is None: return jsonify(error='Should not happen ...'), 500 return jsonify(id=user.id, email=user.email), 200 return jsonify(error='never reach here...'), 500
อีกครั้งเราใช้ประโยชน์จากโมดูล jwt เพื่อถอดรหัสโทเค็น JWT ที่รวมอยู่ในส่วนหัว 'Authorization' และจัดการกับกรณีที่โทเค็นหมดอายุหรือไม่ถูกต้อง
ลองทดสอบจุดสิ้นสุดนี้โดยใช้ curl ขั้นแรกเราต้องได้รับโทเค็นที่ถูกต้อง:
curl localhost:5000/auth/signup -H 'Content-Type: application/json' -X POST -d '{'email':' [email protected] ','password':'xyz'}'
จากนั้นด้วยโทเค็นนี้:
curl localhost:5000/user -H 'Authorization: Bearer {put the token here}'
ซึ่งให้ผลลัพธ์นี้:
มอนติคาร์โลจำลองการแจกแจงแบบปกติ
{ 'email': ' [email protected] ', 'id': 1 }
ตอนนี้เราต้องรวมจุดสิ้นสุดนี้ไว้ใน Secret Controller นี่ค่อนข้างง่ายเพราะเราต้องเรียกจุดสิ้นสุดโดยใช้โมดูล $ http ปกติ Satellizer จะแทรกโทเค็นไปยังส่วนหัวโดยอัตโนมัติดังนั้นเราจึงไม่จำเป็นต้องกังวลกับรายละเอียดทั้งหมดของการบันทึกโทเค็นจากนั้นจึงวางไว้ในส่วนหัวที่ถูกต้อง
getUserInfo(); function getUserInfo() { $http.get('/user') .then(function (response) { $scope.user = response.data; }) .catch(function (response) { console.log('getUserInfo error', response); }) }
ในที่สุดเราก็มีบางสิ่งที่เป็นส่วนตัวอย่างแท้จริงในหน้าลับ!
รหัสของขั้นตอนนี้เปิดอยู่ GitHub .
สิ่งที่ดีเกี่ยวกับ Satellizer ดังที่กล่าวไว้ในตอนต้นคือทำให้การรวมการเข้าสู่ระบบโซเชียลง่ายขึ้นมาก ในตอนท้ายของขั้นตอนนี้ผู้ใช้สามารถเข้าสู่ระบบโดยใช้บัญชี Facebook ได้!
สิ่งแรกที่ต้องทำคือการสร้างแอปพลิเคชันบนหน้านักพัฒนา Facebook เพื่อให้มีไฟล์ application_id และรหัสลับ โปรดติดตาม Developers.facebook.com/docs/apps/register เพื่อสร้างบัญชีผู้พัฒนา Facebook หากคุณยังไม่มีและสร้างแอปเว็บไซต์ หลังจากนั้นคุณจะมีรหัสแอปพลิเคชันและความลับของแอปพลิเคชันดังภาพหน้าจอด้านล่าง
เมื่อผู้ใช้เลือกเชื่อมต่อกับ Facebook แล้ว Satellizer จะส่งรหัสการอนุญาตไปยังปลายทาง / auth / facebook . ด้วยรหัสการอนุญาตนี้แบ็คเอนด์สามารถดึงโทเค็นการเข้าถึงจาก Facebook / oauth endpoint ที่อนุญาตให้โทรไปยัง Facebook Graph API เพื่อรับข้อมูลผู้ใช้เช่นตำแหน่งที่ตั้ง user_friends อีเมลผู้ใช้ ฯลฯ
นอกจากนี้เรายังต้องติดตามด้วยว่าบัญชีผู้ใช้ถูกสร้างขึ้นด้วย Facebook หรือผ่านการสมัครใช้งานปกติ ในการทำเช่นนั้นเราเพิ่ม ชื่อผู้ใช้เฟสบุ๊ค ไปยังรูปแบบผู้ใช้ของเรา
facebook_id = db.Column(db.String(100))
ความลับของ Facebook ถูกกำหนดค่าผ่านตัวแปร env FACEBOOK_SECRET ที่เราเพิ่มเข้าไป app.config .
app.config['FACEBOOK_SECRET'] = os.environ.get('FACEBOOK_SECRET')
เพื่อเปิดตัว app.py คุณควรตั้งค่าตัวแปร env นี้:
FACEBOOK_SECRET={your secret} python app.py
นี่คือวิธีการจัดการการเข้าสู่ระบบ Facebook โดยค่าเริ่มต้น Satellizer จะเรียกจุดสิ้นสุด / auth / facebook .
@app.route('/auth/facebook', methods=['POST']) def auth_facebook(): access_token_url = 'https://graph.facebook.com/v2.3/oauth/access_token' graph_api_url = 'https://graph.facebook.com/v2.5/me?fields=id,email' params = { 'client_id': request.json['clientId'], 'redirect_uri': request.json['redirectUri'], 'client_secret': app.config['FACEBOOK_SECRET'], 'code': request.json['code'] } # Exchange authorization code for access token. r = requests.get(access_token_url, params=params) # use json.loads instead of urlparse.parse_qsl access_token = json.loads(r.text) # Step 2. Retrieve information about the current user. r = requests.get(graph_api_url, params=access_token) profile = json.loads(r.text) # Step 3. Create a new account or return an existing one. user = User.query.filter_by(facebook_id=profile['id']).first() if user: return jsonify(token=user.token()) u = User(facebook_id=profile['id'], email=profile['email']) db.session.add(u) db.session.commit() return jsonify(token=u.token())
ในการส่งคำขอไปยังเซิร์ฟเวอร์ Facebook เราใช้คำขอโมดูลที่มีประโยชน์ ตอนนี้ส่วนที่ยากในส่วนหลังเสร็จสิ้นแล้ว ในส่วนหน้าการเพิ่มการเข้าสู่ระบบ Facebook นั้นค่อนข้างง่าย ขั้นแรกเราต้องบอก Satellizer ของเรา ชื่อผู้ใช้เฟสบุ๊ค โดยเพิ่มรหัสนี้ลงใน app.config ฟังก์ชัน:
$authProvider.facebook({ clientId: {your facebook app id}, // by default, the redirect URI is http://localhost:5000 redirectUri: 'http://localhost:5000/static/index.html' });
ในการเข้าสู่ระบบโดยใช้ Facebook เราสามารถโทร:
$auth.authenticate(“facebook”)
ตามปกติคุณสามารถตรวจสอบไฟล์ รหัสบน GitHub
ในขณะนี้ webapp มีความสมบูรณ์ในแง่ของฟังก์ชันการทำงาน ผู้ใช้สามารถเข้าสู่ระบบ / ลงทะเบียนโดยใช้อีเมลและรหัสผ่านปกติหรือโดยใช้ Facebook เมื่อเข้าสู่ระบบแล้วผู้ใช้จะเห็นหน้าลับของเขา
ในตอนนี้อินเทอร์เฟซไม่ค่อยสวยนักดังนั้นเรามาเพิ่ม Bootstrap เล็กน้อยสำหรับเลย์เอาต์และโมดูลเครื่องปิ้งขนมปังเชิงมุมเพื่อจัดการกับข้อความแสดงข้อผิดพลาดอย่างดีเช่นเมื่อการเข้าสู่ระบบล้มเหลว
รหัสสำหรับส่วนที่สวยงามนี้สามารถพบได้ ที่นี่ .
บทความนี้แสดงการรวม Satellizer แบบทีละขั้นตอนในเว็บแอพ AngularJS (แบบง่าย) ด้วย Satellizer เราสามารถเพิ่มการเข้าสู่ระบบโซเชียลอื่น ๆ เช่น Twitter, Linkedin และอื่น ๆ ได้อย่างง่ายดาย โค้ดที่อยู่ส่วนหน้าค่อนข้างเหมือนกับในบทความ อย่างไรก็ตามส่วนหลังแตกต่างกันไปเนื่องจาก SDK เครือข่ายโซเชียลมีจุดสิ้นสุดที่แตกต่างกันโดยมีโปรโตคอลที่แตกต่างกัน คุณสามารถดูได้ที่ https://github.com/sahat/satellizer/blob/master/examples/server/python/app.py ซึ่งมีตัวอย่างสำหรับ Facebook, Github, Google, Linkedin, Twiter และ Bitbucket หากมีข้อสงสัยคุณควรดูเอกสารประกอบบน https://github.com/sahat/satellizer .
ที่เกี่ยวข้อง: คลิกเดียวเข้าสู่ระบบด้วย Blockchain: บทช่วยสอน MetaMask