Cara mengadaptasi UX / UI di bawah izin

Banyak proyek memiliki proses autentikasi (sampai tingkat tertentu). Banyak praktik terbaik telah ditulis dalam semua teknologi yang dikenal, dll. dll.


Tetapi pengguna membuat login dan? Toh, dia tidak bisa melakukan semuanya. Cara menentukan apa yang bisa dia lihat dan apa yang tidak. Tombol mana yang berhak untuk ditekan, yang dapat mengubah apa yang harus dibuat atau dihapus.


Pada artikel ini saya ingin mempertimbangkan pendekatan untuk menyelesaikan masalah ini pada aplikasi web.


gambar


Untuk memulainya, otorisasi nyata / efektif hanya dapat terjadi di server. Di Front End, kami hanya dapat meningkatkan antarmuka pengguna (hmm, bahasa Rusia kuat, tetapi tidak selalu ...), itu juga Pengalaman Pengguna di luar UX. Kami dapat menyembunyikan tombol di mana pengguna tidak memiliki hak untuk mengklik, atau mencegahnya mengakses halaman, atau menunjukkan pesan bahwa ia tidak memiliki hak untuk tindakan ini atau itu.


Dan di sini muncul pertanyaan, bagaimana melakukannya seakurat mungkin.


Mari kita mulai dengan mendefinisikan masalahnya.


Kami menciptakan Aplikasi Todo dan memiliki berbagai jenis pengguna:


USER - dapat melihat semua tugas dan mengubahnya (mengatur dan menghapus V), tetapi tidak dapat menghapus atau membuat dan tidak melihat statistik.


ADMIN - dapat melihat semua tugas dan membuat yang baru, tetapi tidak melihat statistik.


SUPER_ADMIN - dapat melihat semua tugas, membuat yang baru dan menghapus, juga dapat melihat statistik.


lihat tugasBuat tugascentang / hapus centang tugas (perbarui)hapus tugaslihat statistik
PENGGUNAVXVXX
AdminVVVXX
SUPER_ADMINVVVVV

Dalam situasi seperti itu, kita dapat dengan mudah bertahan dengan perannya. Namun, situasinya dapat berubah banyak. Bayangkan bahwa ada pengguna yang harus memiliki hak yang sama dengan ADMIN plus menghapus tugas. Atau hanya PENGGUNA dengan kemampuan untuk melihat statistik.


Solusi sederhana adalah menciptakan peran baru.
Tetapi pada sistem besar, dengan jumlah pengguna yang relatif besar, kami akan dengan cepat tersesat dalam sejumlah besar peran ... Dan di sini kita mengingat izin "hak pengguna". Untuk manajemen yang lebih mudah, kami dapat membuat grup dengan beberapa izin dan melampirkannya ke pengguna. Selalu ada peluang untuk menambahkan izin khusus ke pengguna tertentu.


Solusi serupa dapat ditemukan di banyak layanan hebat. AWS, Google Cloud, SalesForce, dll.
Juga, solusi serupa sudah diterapkan di banyak kerangka kerja, misalnya, Django (python).


Saya ingin memberikan contoh implementasi untuk aplikasi Angular. (Pada contoh Aplikasi ToDo yang sama).


Pertama, Anda perlu menentukan semua izin yang mungkin.


Dibagi menjadi beberapa fitur


  1. Kami memiliki tugas dan statistik.
  2. Kami menentukan tindakan yang mungkin dilakukan untuk masing-masing tindakan tersebut.
    • Tugas: membuat, membaca, memperbarui, menghapus
    • Statistik: baca (dalam contoh kami, hanya lihat)
  3. Buat peta (MAP) peran dan izin

export const permissionsMap = { todos:{ create:'*', read:'*', update:'*', delete:'*' }, stats:'*' } 

Menurut pendapat saya ini adalah pilihan terbaik, tetapi dalam banyak kasus server akan mengembalikan sesuatu seperti ini:


 export permissions = [ 'todos_create', 'todos_read', 'todos_update', 'todos_delete', 'stas' ] 

Kurang mudah dibaca, tetapi juga sangat bagus.


Seperti inilah tampilan aplikasi kita jika pengguna memiliki semua izin yang memungkinkan.


gambar


Mari kita mulai dengan USER, seperti inilah perizinannya:


 export const USERpermissionsMap = { todos:{ read:'*', update:'*', } } 

1) USER tidak dapat melihat statistik, yaitu, pada prinsipnya, itu tidak dapat pergi ke halaman statistik.


Untuk situasi seperti itu, Angular memiliki Pengawal, yang terdaftar di tingkat Rute ( dokumentasi ).


Dalam kasus kami, tampilannya seperti ini:


 const routes: Routes = [ // {...Other routes}, { path: 'stats', component: TodoStatisticsComponent, canActivate: [ PermissionsGuardService ], data: { permission: 'stats' }, } ]; 

Anda harus memperhatikan objek dalam data.


peremissions = 'stats', ini adalah izin yang harus dimiliki pengguna untuk memiliki akses ke halaman ini.


Berdasarkan pada data.permissions yang diperlukan dan izin yang diberikan oleh server PermissionsGuardService, ia akan memutuskan apakah akan membiarkan USER membuka laman '/ stats'.


 @Injectable({ providedIn: 'root' }) export class PermissionsGuardService implements CanActivate { constructor( private store: Store<any>) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { // Required permission to continue navigation const required = route.data.permission; // User permissions that we got from server const userPerms = this.getPermissions(); // verification const isPermitted = checkPermissions(required, userPerms); if (!isPermitted) { alert('ROUTE GUARD SAYS: \n You don\'t have permissions to see this page'); } return isPermitted; } getPermissions() { return localStorage.get('userPermissions') } } 

Fungsi ini berisi logika keputusan - apakah ada izin yang tidak tergantikan (wajib) ada di antara semua izin PENGGUNA (userPerms).


 export function checkPermissions(required: string, userPerms) { // 1) Separate feature and action const [feature, action] = required.split('_'); // 2) Check if user have any type of access to the feature if (!userPerms.hasOwnProperty(feature)) { return false; } // 3) Check if user have permission for required action if (!userPerms[feature].hasOwnProperty(action)) { return false; } return true; } 

gambar


Dan begitulah. USER kami tidak dapat membuka halaman statistik. Namun, ia masih dapat membuat tugas dan menghapusnya.


Agar USER tidak dapat menghapus tugas, itu akan cukup untuk menghapus merah (X) dari baris tugas.
Untuk tujuan ini kita akan menggunakan Petunjuk Struktural .


 <!-- Similar to other Structural Directives in angular (*ngIF, *ngFor..) we have '*' in directive name Input for directive is a required permission to see this btn. --> <button *appPermissions="'todos_delete'" class="delete-button" (click)="removeSingleTodo()"> X </button> 

 @Directive({ selector: '[appPermissions]' }) export class PermissionsDirective { private _required: string; private _viewRef: EmbeddedViewRef<any> | null = null; private _templateRef: TemplateRef<any> | null = null; @Input() set appPermissions(permission: string) { this._required = permission; this._viewRef = null; this.init(); } constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef) { this._templateRef = templateRef; } init() { const isPermitted = checkPermissions(this._required, this.getPermissions()); if (isPermitted) { this._viewRef = this.viewContainerRef.createEmbeddedView(this.templateRef); } else { console.log('PERMISSIONS DIRECTIVE says \n You don\'t have permissions to see it'); } } getPermissions() { localStorage.get('userPermissions') } } 

gambar


Sekarang USER tidak melihat tombol DELETE tetapi masih bisa menambahkan tugas baru.


Untuk menghapus bidang input - akan merusak semua jenis aplikasi kita. Solusi yang benar dalam situasi ini adalah disable bidang input.


Kami akan menggunakan pipa.


 <!-- as a value `permissions` pipe will get required permissions `permissions` pipe return true or false, that's why we have !('todos_create' | permissions) to set disable=true if pipe returns false --> <input class="centered-block" [disabled]="!('todos_create' | permissions)" placeholder="What needs to be done?" autofocus/> 

 @Pipe({ name: 'permissions' }) export class PermissionsPipe implements PipeTransform { constructor(private store: Store<any>) { } transform(required: any, args?: any): any { const isPermitted = checkPermissions(required, this.getPermissions()); if (isPermitted) { return true; } else { console.log('[PERMISSIONS PIPE] You don\'t have permissions'); return false; } } getPermissions() { return localStorage.get('userPermissions') } } 

Dan sekarang USER hanya bisa melihat tugas dan mengubahnya (V / X). Namun, kami masih memiliki satu tombol lagi yang disebut 'Hapus selesai'.


Misalkan kita memiliki persyaratan Manajer Produk berikut:


  1. Tombol 'Clear Completed' harus terlihat oleh semua orang dan selalu.
  2. Itu juga harus bisa diklik.
  3. Jika USER tanpa izin yang sesuai menekan tombol, sebuah pesan akan muncul.

Arahan konstruksi tidak akan membantu kita, juga pipa.
Juga sangat tidak nyaman untuk menulis izin yang memeriksa fungsi komponen.


Yang kita butuhkan adalah melakukan pemeriksaan izin antara klik dan eksekusi fungsi terikat.


Menurut pendapat saya, layak menggunakan dekorator.


 export function Permissions(required) { return (classProto, propertyKey, descriptor) => { const originalFunction = descriptor.value; descriptor.value = function (...args: any[]) { const userPerms = localStorage.get('userPermissions') const isPermitted = checkPermissions(required, userPerms); if (isPermitted) { originalFunction.apply(this, args); } else { alert('you have no permissions \n [PERMISSIONS DECORATOR]'); } }; return descriptor; }; } 

 @Component({ selector: 'app-actions', templateUrl: './actions.component.html', styleUrls: ['./actions.component.css'] }) export class ActionsComponent implements OnInit { @Output() deleteCompleted = new EventEmitter(); constructor() { } @Permissions('todos_delete') public deleteCompleted() { this.deleteCompleted.emit(); } } 

Pembicara berhak mendapatkan artikel terpisah.


Hasil akhir kami:


gambar


Hasilnya:


Pendekatan ini memungkinkan kami untuk dengan mudah dan dinamis menyesuaikan UX kami sesuai dengan izin yang dimiliki pengguna.


Dan yang paling penting, untuk ini kita tidak perlu mendorong layanan ke semua komponen atau palu di templat '* ngIf'.


Seluruh aplikasi selesai .


Saya akan senang berkomentar.

Source: https://habr.com/ru/post/id439100/


All Articles