پیاده سازی سیستم دسترسی در انگیولار حسن قاسمی
پیاده سازی سیستم دسترسی در انگیولار

سیستم دسترسی

در سیستم های احراز هویت مبتنی بر دسترسی، برای هر منبع(Resource) یک دسترسی مجزا تعریف می شود. بطور مثال می توان عملیات چهارگانه افزودن، بروز رسانی، حذف و خواندن را برای هر ویژگی برنامه (مدیریت مطالب، مدیریت کاربران) در نظر گرفت که از دید طراحی پایگاه داده بصورت یک رابطه چند به چند بصورت زیر می باشد.

- طرح فوق صرفاً یک مثال و طرح ابتدایی برای سیستم احراز هویت مبتنی بر دسترسی می باشد.

بطور مثال در یک فروشگاه اینترنتی یک نمونه دسترسی برای موجودیت محصول به صورت زیر می باشد.

1. add-product

2. update-product

3. delete-product

4. read-product

برای سایر ویژگی ها (سفارش، پرداخت و ...) نیز همین روش را می توان بکار برد.

 

پیش نیازها

بطور کلی برای پیاده سازی این سیستم در برنامه انگیولار موارد زیر انجام خواهد شد:

- تغییر در سرویس احراز هویت و کنترل دسترسی ها

- افزودن guard برای کنترل مسیرها بر اساس دسترسی مشخص شده

- تغییرات در تعریف مسیرها و مشخص کردن دسترسی برای هر مسیر

 

پیاده سازی

ابتدا تغییرات موردنیاز در سرویس احراز هویت را اعمال می کنیم.

get isAuthenticated(): boolean {
    if(this._acc.userInfo){
      return true;
    }
    return false;
  }

  hasPermission(permission: string): boolean {
    if(!this.isAuthenticated) {
      return false;
    }

    const authorized = this._acc.userInfo.permissions.split(',').filter(x => {
      return permission.split(',').indexOf(x) !== -1 ? true:false;
    });
    if(authorized.length > 0) {
      return true;
    }
    return false;    
  }

در کد بالا متد isAuthenticated وضعیت جاری کاربر را (لاگین شده است یا خیر) مشخص می کند که منطق اینکار بر اساس نیازهای پروژه تعریف می شود و تاثیری در روش پیاده سازی سیستم دسترسی نخواهد داشت. بخش اصلی کار مربوط به متد hasPermission است. این متد پس از اطمینان از اینکه کاربر لاگین شده است دسترسی وی را بر اساس پارامتر ورودی متد بررسی می کند. در این مثال فرض شده است تمام دسترسی های کاربر پس از لاگین در یک متغییر به نام permissions ذخیره شده است. مثلا اگر پارامتر ورودی متد add-product باشد این متد add-product را در لیست دسترسی های کاربر جستجو خواهد کرد و مقدار true و false را بر این اساس برگشت خواهد داد.

پس از اعمال تغییرات در سیستم احراز هویت، یک guard با نام auth.guard.ts برای بررسی دسترسی در مسیرها اضافه می کنیم.

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
    constructor(
        private _router: Router,
        private _authService: AuthenticationService
    ) {}

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {        
        if (this._authService.hasPermission(route.data.permission)) {            
            return true;
        }

        // not logged in so redirect to login page with the return url
        this._router.navigate(['/auth/login'], { queryParams: { returnUrl: state.url }});
        return false;
    }
}

در متد canActivate در خط اول سرویس احراز هویت و متدی که قبلا پیاده سازی شده است فراخوانی می شود. ورودی متد hasPermission، مقداری است که در بعدا هنگام تعریف مسیر در متغییر data قرار خواهیم داد. در صورتیکه کاربر دسترسی مشخص شده در data را نداشته باشد، به صفحه login هدایت خواهد شد.

با انجام تغییرات موردنیاز، اکنون پیش نیازهای استفاده از سیستم دسترسی آماده شده است و فقط باید برای مسیرهای موردنظر، دسترسی ها را تعریف کنیم. اینکار با استفاده از متغییر data انجام می گیرد. این متغیر بصورت پیش فرض و توسط انگیولار برای انتقال داده در مسیرها استفاده می شود و می توان یک مقدار رشته ای و حتی یک object را از این طریق به مسیرهای دیگر انتقال داد و در مقصد از طریق متغییری با همین نام از ActivatedRouteSnapshot دریافت کرد. مثلا برای یک ماژول با نام Shop که مجموعه ای از کامپوننت های دیگر را شامل می شود مسیر زیر در app-routing.module.ts تعریف شده است.

const routes: Routes = [
  {
    path: '', component: ShopLayoutComponent,
    loadChildren: './modules/public/shop/shop.module#ShopModule',
    canActivate: [AuthGuard],
    data: {
     permission: 'read-product, add-product'
    }
  }
];

در مسیر موردنظر، برای کنترل دسترسی ها از guard تعریف شده در مراحل قبل استفاده شده است و دسترسی های موردنیاز برای مسیر نیز از طریق متغییر data اضافه شده است. البته با توجه به نحوه دسترسی ماژول ها می توان دسترسی های هر مسیر را دقیق تر و تمیزتر مشخص کرد. مثلا می توان برای ماژول  Shop یک دسترسی کلی read-product مشخص کرد ولی در داخل این ماژول برای هر عملکرد، یک ماژول جداگانه تعریف کرد. مثلا برای افزودن یک محصول یک ماژول جداگانه تعریف کرد و در فایل shop-routing.module.ts در متغییر data برای مسیر ماژول تازه ایجاد شده، دسترسی را بصورت add-product اضافه کرد. برای عملکردهای دیگر نیز به همین ترتیب عمل کرد که اینکار انعطاف پذیری و کنترل دسترسی ها را راحت تر خواهد کرد.

 

خلاصه

سیستم احراز هویت مبتنی بر دسترسی معمولا در پروژه های بزرگ و با تعداد کاربر زیاد مورد استفاده قرار می گیرد و در سیستم های کوچک می توان از طریق role احراز هویت و کنترل دسترسی ها را انجام داد و نیاز نیست برای هر عملکرد در پروژه، بصورت مجزا دسترسی افزودن، حذف و ... تعریف شود. برای پیاده سازی دسترسی ها در پروژه های انگیولار، در این مقاله یک روش ساده ارائه شد که با استفاده از ماژول بندی مناسب می توان آن را کامل تر و کاربردی تر بازنویسی و استفاده کرد.

Copyright © 2019 | Jvpars.com All Rights Reserved.