การรับรองความถูกต้อง
วิธีที่พบบ่อยที่สุดในการออกแบบสิทธิ์คือการควบคุมการเข้าถึงตามบทบาทของ RBAC แนวคิดพื้นฐานคือการอนุญาตที่หลากหลายสำหรับการดำเนินงานระบบจะไม่ได้รับมอบให้กับผู้ใช้ที่เฉพาะเจาะจงโดยตรง แต่เพื่อสร้างการรวบรวมบทบาทระหว่างชุดผู้ใช้และชุดสิทธิ์ แต่ละบทบาทสอดคล้องกับชุดสิทธิ์ที่สอดคล้องกัน
เมื่อผู้ใช้ได้รับการกำหนดบทบาทที่เหมาะสมผู้ใช้จะมีสิทธิ์ในการดำเนินงานทั้งหมดสำหรับบทบาท ข้อดีของสิ่งนี้คือไม่จำเป็นต้องกำหนดสิทธิ์ทุกครั้งที่ผู้ใช้ถูกสร้างขึ้นเพียงแค่กำหนดบทบาทที่สอดคล้องกันของผู้ใช้และการเปลี่ยนแปลงการอนุญาตของบทบาทนั้นน้อยกว่าการเปลี่ยนแปลงการอนุญาตของผู้ใช้ซึ่งจะทำให้การจัดการการอนุญาตของผู้ใช้ง่ายขึ้นและลดค่าใช้จ่ายของระบบ
ในแอปพลิเคชันหน้าเดียวที่สร้างโดย Angular เราต้องทำสิ่งพิเศษเพื่อใช้สถาปัตยกรรมดังกล่าว จากมุมมองของโครงการโดยรวมมีประมาณ 3 แห่งที่วิศวกรส่วนหน้าต้องจัดการ
1. การประมวลผล UI (ตัดสินว่าเนื้อหาบางส่วนในหน้าจะแสดงขึ้นอยู่กับการอนุญาตที่เป็นเจ้าของโดยผู้ใช้หรือไม่)
2. การประมวลผลการกำหนดเส้นทาง (เมื่อผู้ใช้เข้าถึง URL ที่ไม่มีสิทธิ์ในการเข้าถึงมันจะข้ามไปยังหน้าด้วยข้อความแสดงข้อผิดพลาด)
3. การประมวลผลคำขอ HTTP (เมื่อเราส่งคำขอข้อมูลหากสถานะที่ส่งคืนคือ 401 หรือ 403 มักจะเปลี่ยนเส้นทางไปยังหน้าด้วยข้อความแสดงข้อผิดพลาด)
การใช้งานการควบคุมการเข้าถึงข้อมูลประจำตัว
ก่อนอื่นคุณต้องได้รับสิทธิ์ทั้งหมดของผู้ใช้ปัจจุบันก่อนที่จะเริ่มต้นเชิงมุมและจากนั้นวิธีที่สง่างามยิ่งขึ้นคือการจัดเก็บความสัมพันธ์การทำแผนที่นี้ผ่านบริการ สำหรับเนื้อหาในหน้าเว็บจะแสดงตามสิทธิ์โดย UI หรือไม่ หลังจากประมวลผลสิ่งเหล่านี้เราต้องเพิ่มแอตทริบิวต์ "อนุญาต" เพิ่มเติมเพื่อเพิ่มเส้นทางเมื่อเพิ่มเส้นทางและกำหนดค่าเพื่อระบุบทบาทที่มีสิทธิ์สามารถข้ามไปยัง URL นี้แล้วฟังเหตุการณ์ RouteChangestart ผ่าน Angular เพื่อตรวจสอบว่าผู้ใช้ปัจจุบันสามารถเข้าถึง URL นี้ได้หรือไม่ ในที่สุดจำเป็นต้องมีการสกัดกั้น HTTP เพื่อตรวจสอบเมื่อสถานะส่งคืนโดยคำขอคือ 401 หรือ 403 ข้ามไปที่หน้าไปยังหน้าพรอมต์ข้อผิดพลาด นี่คือสิ่งที่มันเป็นสิ่งที่ดูเหมือนมากเกินไป แต่จริงๆแล้วมันง่ายมากที่จะจัดการกับ
ส่งคืน 401, ดำเนินการ loginctrl, return 403, ดำเนินการ PermissionCtrl
รับความสัมพันธ์การทำแผนที่ของการอนุญาตก่อนที่จะทำงานเชิงมุม
โครงการเชิงมุมเริ่มต้นผ่าน NG-APP แต่ในบางกรณีเราหวังว่าโครงการเชิงมุมจะอยู่ภายใต้การควบคุมของเรา ตัวอย่างเช่นในกรณีนี้ฉันหวังว่าจะได้รับความสัมพันธ์การแมปการอนุญาตทั้งหมดของผู้ใช้ที่เข้าสู่ระบบในปัจจุบันแล้วเริ่มแอพเชิงมุม โชคดีที่ Angular ให้วิธีนี้นั่นคือ Angular.bootstrap ()
Var PermissionList; Angular.element (เอกสาร) .ready (function () {$ .get ('/api/userpermission', ฟังก์ชั่น (ข้อมูล) {permissionList = data; angular.bootstrap (เอกสาร, ['app']);});});ผู้ที่อ่านอย่างระมัดระวังอาจสังเกตเห็นว่าการใช้ $ .get () ถูกใช้ที่นี่และไม่มีข้อผิดพลาดในการใช้ jQuery แทนทรัพยากร $ ของ Angular หรือ $ http เพราะในเวลานี้ Angular ยังไม่ได้เริ่มต้นและเราไม่สามารถใช้ฟังก์ชั่นได้
ใช้รหัสข้างต้นเพิ่มเติมเพื่อใส่ความสัมพันธ์การแมปที่ได้รับลงในบริการเป็นตัวแปรทั่วโลก
// app.js var app = angular.module ('myapp', []), permissionList; app.run (ฟังก์ชั่น (สิทธิ์) {permissions.setPermissions (PermissionList)}); Angular.element (เอกสาร) .ready (function () {$ .get ('/api/userpermission', ฟังก์ชั่น (ข้อมูล) {permissionList = data; angular.bootstrap (เอกสาร, ['app']);});}); // Common_service.js Angular.module ('MyApp') .Factory ('การอนุญาต', ฟังก์ชั่น ($ rootscope) {var permissionList; return {setPermissions: ฟังก์ชั่น (การอนุญาต) {permissionList = การอนุญาต; $ rootscope. $ broadcopeหลังจากได้รับชุดสิทธิ์ของผู้ใช้ปัจจุบันเราเก็บถาวรชุดนี้ไว้ในบริการที่เกี่ยวข้องแล้วทำอีก 2 สิ่ง:
(1) การจัดเก็บสิทธิ์ในตัวแปรโรงงานเพื่อให้พวกเขาอยู่ในความทรงจำเสมอตระหนักถึงบทบาทของตัวแปรทั่วโลก แต่ไม่ก่อให้เกิดมลพิษเนมสเปซ
(2) เหตุการณ์ออกอากาศผ่าน $ Broadcast เมื่อการอนุญาตเปลี่ยน
1. วิธีการกำหนดพลังที่มองเห็นและซ่อนเร้นขององค์ประกอบ UI ตามการอนุญาต
ที่นี่เราต้องเขียนคำสั่งตัวเองซึ่งจะแสดงหรือซ่อนองค์ประกอบตามความสัมพันธ์การอนุญาต
<!-หากผู้ใช้มีการแก้ไขการแสดงลิงก์-> <div have-permission = 'แก้ไข'> <a href = "/#/courses/{{id}}/แก้ไข"> {{name}} </a> </div> <! Hast-Permission = '! แก้ไข'> {{ชื่อ}} </div>ที่นี่ฉันเห็นสถานการณ์ในอุดมคติที่คุณสามารถผ่านชื่อสิทธิ์การตรวจสอบคุณสมบัติที่ได้รับการรับรองและหากผู้ใช้ปัจจุบันมีมันจะปรากฏขึ้นและหากไม่มีมันจะถูกซ่อนไว้
Angular.Module ('myApp'). Directive ('Haspermission', ฟังก์ชั่น (การอนุญาต) {return {link: function (ขอบเขต, องค์ประกอบ, attrs) {ถ้า (! _. isstring (attrs.haspermission) การโยน "ค่า haspermission จะต้องเป็นสตริง"; var value = attrs.haspermission.trim () if (notpermissionflag) {value = value.slice (1) .trim (); Togglevisablebasedonpermission ();ขยายโรงงานก่อนหน้า:
Angular.Module ('MyApp') .Factory ('สิทธิ์', ฟังก์ชั่น ($ rootscope) {permissionList var; return {setPermissions: ฟังก์ชั่น (การอนุญาต) {permissionList = สิทธิ์; $ rootscope. $ broadcast ('permissions _.some (PermissionList, ฟังก์ชั่น (รายการ) {ถ้า _. isstring (item.name)) return item.name.trim () === การอนุญาต});2. การเข้าถึงตามการอนุญาตบนเส้นทาง
แนวคิดของการใช้งานส่วนนี้มีดังนี้: เมื่อเรากำหนดเส้นทางเราเพิ่มแอตทริบิวต์การอนุญาตและค่าของแอตทริบิวต์คือสิ่งที่เราต้องเข้าถึง URL ปัจจุบัน จากนั้นเราฟังการเปลี่ยนแปลง URL ผ่านเหตุการณ์ RouteChangestart ทุกครั้งที่เราเปลี่ยน URL ตรวจสอบว่า URL ที่จะเปลี่ยนเส้นทางตรงตามเงื่อนไขและตัดสินใจว่าจะเปลี่ยนเส้นทางได้สำเร็จหรือไปยังหน้าพรอมต์ข้อผิดพลาด
app.config (ฟังก์ชั่น ($ routeprovider) {$ routeProvider. เมื่อ ('/', {templateurl: 'views/viewCourses.html', คอนโทรลเลอร์: 'ViewCoursesctrl'}). เมื่อ '/unauthorized', {templateurl: . เมื่อ ('/courses/: id/แก้ไข', {templateurl: 'views/editcourses.html', คอนโทรลเลอร์: 'editcourses', การอนุญาต: 'แก้ไข'});});mainController.js หรือ indexcontroller.js (โดยย่อคือตัวควบคุมเลเยอร์พาเรนต์)
app.controller ('mainappctrl', ฟังก์ชั่น ($ scope, $ ตำแหน่ง, การอนุญาต) {$ scope. $ on ('$ routechangestart', ฟังก์ชั่น (ขอบเขต, ถัดไป, ปัจจุบัน) {การอนุญาต var = ถัดไป. -Haspermission ที่เขียนไว้ก่อนจะยังคงใช้ที่นี่และสิ่งเหล่านี้สามารถนำกลับมาใช้ใหม่ได้อย่างมาก ทำเสร็จแล้ว ก่อนที่จะข้ามเส้นทางการดูแต่ละครั้งเพียงตัดสินว่าจะได้รับอนุญาตให้กระโดดในคอนโทรลเลอร์ของคอนเทนเนอร์หลักหรือไม่
3. การประมวลผลคำขอ http
สิ่งนี้น่าจะค่อนข้างง่ายที่จะจัดการและความคิดนั้นง่ายมาก เนื่องจากแอพพลิเคชั่นเชิงมุมแนะนำข้อแก้ตัวสไตล์การพักผ่อนการใช้โปรโตคอล HTTP จึงชัดเจนมาก หากรหัสสถานะที่ส่งคืนโดยคำขอคือ 401 หรือ 403 หมายความว่าไม่มีการอนุญาตดังนั้นคุณสามารถข้ามไปยังหน้าพรอมต์ข้อผิดพลาดที่เกี่ยวข้อง
แน่นอนว่าเราไม่สามารถตรวจสอบและส่งต่อการร้องขอแต่ละครั้งได้ด้วยตนเองดังนั้นเราต้องต้องใช้ตัวกรองทั้งหมดอย่างแน่นอน รหัสมีดังนี้:
Angular.module ('myapp') .config (ฟังก์ชั่น ($ httpprovider) {$ httpprovider.responseInterceptors.push ('SecurityInterceptor');}) .provider ('SecurityInterceptor', ฟังก์ชัน () if (response.status === 403 || responds.status === 401) {$ location.path ('/unauthorized');โดยการเขียนสิ่งนี้คุณสามารถตระหนักถึงการจัดการการอนุญาตและการควบคุมส่วนหน้าในโหมดการแยกส่วนหน้านี้
รูปแบบการยืนยัน
คำสั่งการตรวจสอบส่วนหน้าของ AngularJS
var rcsubmitDirective = {'rcsubmit': ฟังก์ชั่น ($ parse) {return {จำกัด : "a", ต้องการ: ["rcsubmit", "? form"], คอนโทรลเลอร์: function () {this.athemped = false; var formController = null; this.setAttempted = function () {this.attempted = true; - this.setFormController = ฟังก์ชั่น (คอนโทรลเลอร์) {formController = คอนโทรลเลอร์; - this.needsattention = function (FieldModelController) {ถ้า (! formController) ส่งคืนเท็จ; if (FieldModelController) {ส่งคืน FieldModelController $ INVALID && (FieldModelController. $ DIRTIC || this.Attempted); } else {return formController && formController. $ ไม่ถูกต้อง && (formController. $ dirty || this.attempted); - }, Compile: function () {return {pre: function (ขอบเขต, formElement, แอตทริบิวต์, คอนโทรลเลอร์) {var submentController = ตัวควบคุม [0]; var formController = controllers.length> 1? คอนโทรลเลอร์ [1]: null; SubmentController.SetFormController (FormController); prope.rc = scope.rc || - prope.rc [attributes.name] = submitcontroller; }, โพสต์: ฟังก์ชั่น (ขอบเขต, รูปแบบ, แอตทริบิวต์, คอนโทรลเลอร์) {var submentController = ตัวควบคุม [0]; var formController = controllers.length> 1? คอนโทรลเลอร์ [1]: null; var fn = $ parse (attributes.rcsubmit); formElement.bind ("ส่ง", ฟังก์ชั่น (เหตุการณ์) {submentcontroller.setAttempted (); ถ้า (! ขอบเขต $$ เฟส) ขอบเขต. $ ใช้ (); ถ้า (! formController. $ ถูกต้อง) กลับมา; - - - - - - - - -ผ่านการตรวจสอบ
<form name = "loginform" novalidate ng-app = "loginapp" ng-controller = "logincontroller" rc-submit = "เข้าสู่ระบบ ()"> <div ng-class = "{'have-error': rc.loginform.needsattention ng-model = "session.username"/> <span ng-show = "rc.form.needsattention (loginform.username) && loginform.username. $ error.Required"> จำเป็น </span> </div> type = "password" placeolder = "รหัสผ่าน" จำเป็นต้องใช้ ng-model = "session.password"/> <span ng-show = "rc.form.needsattention (loginform.password) && loginform.password.สไตล์มีดังนี้
เข้าสู่ระบบ () จะถูกเรียกหลังจากผ่านการตรวจสอบส่วนหน้าผ่าน