AccessControl.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. namespace common\modules\rbac\components;
  3. use Yii;
  4. use yii\base\Module;
  5. use yii\di\Instance;
  6. use yii\web\ForbiddenHttpException;
  7. use yii\web\User;
  8. /**
  9. * Access Control Filter (ACF) is a simple authorization method that is best used by applications that only need some simple access control.
  10. * As its name indicates, ACF is an action filter that can be attached to a controller or a module as a behavior.
  11. * ACF will check a set of access rules to make sure the current user can access the requested action.
  12. *
  13. * To use AccessControl, declare it in the application config as behavior.
  14. * For example.
  15. *
  16. * ~~~
  17. * 'as access' => [
  18. * 'class' => 'rbac\components\AccessControl',
  19. * 'allowActions' => ['site/login', 'site/error']
  20. * ]
  21. * ~~~
  22. *
  23. * @property User $user
  24. *
  25. * @author Misbahul D Munir <misbahuldmunir@gmail.com>
  26. *
  27. * @since 1.0
  28. */
  29. class AccessControl extends \yii\base\ActionFilter
  30. {
  31. /**
  32. * @var User User for check access.
  33. */
  34. private $_user = 'user';
  35. /**
  36. * @var array List of action that not need to check access.
  37. */
  38. public $allowActions = [];
  39. /**
  40. * Get user.
  41. *
  42. * @return User
  43. */
  44. public function getUser()
  45. {
  46. if (!$this->_user instanceof User) {
  47. $this->_user = Instance::ensure($this->_user, User::className());
  48. }
  49. return $this->_user;
  50. }
  51. /**
  52. * Set user.
  53. *
  54. * @param User|string $user
  55. */
  56. public function setUser($user)
  57. {
  58. $this->_user = $user;
  59. }
  60. /**
  61. * {@inheritdoc}
  62. */
  63. public function beforeAction($action)
  64. {
  65. $actionId = $action->getUniqueId();
  66. $user = $this->getUser();
  67. if ($user->can('/'.$actionId)) {
  68. return true;
  69. }
  70. $obj = $action->controller;
  71. do {
  72. if ($user->can('/'.ltrim($obj->getUniqueId().'/*', '/'))) {
  73. return true;
  74. }
  75. $obj = $obj->module;
  76. } while ($obj !== null);
  77. $this->denyAccess($user);
  78. }
  79. /**
  80. * Denies the access of the user.
  81. * The default implementation will redirect the user to the login page if he is a guest;
  82. * if the user is already logged, a 403 HTTP exception will be thrown.
  83. *
  84. * @param \yii\web\User $user the current user
  85. *
  86. * @throws \yii\web\ForbiddenHttpException if the user is already logged in.
  87. */
  88. protected function denyAccess($user)
  89. {
  90. if ($user->getIsGuest()) {
  91. $user->loginRequired();
  92. } else {
  93. throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));
  94. }
  95. }
  96. /**
  97. * {@inheritdoc}
  98. */
  99. protected function isActive($action)
  100. {
  101. $uniqueId = $action->getUniqueId();
  102. if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) {
  103. return false;
  104. }
  105. $user = $this->getUser();
  106. if ($user->getIsGuest() && is_array($user->loginUrl) && isset($user->loginUrl[0]) && $uniqueId === trim($user->loginUrl[0], '/')) {
  107. return false;
  108. }
  109. if ($this->owner instanceof Module) {
  110. // convert action uniqueId into an ID relative to the module
  111. $mid = $this->owner->getUniqueId();
  112. $id = $uniqueId;
  113. if ($mid !== '' && strpos($id, $mid.'/') === 0) {
  114. $id = substr($id, strlen($mid) + 1);
  115. }
  116. } else {
  117. $id = $action->id;
  118. }
  119. foreach ($this->allowActions as $route) {
  120. if (substr($route, -1) === '*') {
  121. $route = rtrim($route, '*');
  122. if ($route === '' || strpos($id, $route) === 0) {
  123. return false;
  124. }
  125. } else {
  126. if ($id === $route) {
  127. return false;
  128. }
  129. }
  130. }
  131. if ($action->controller->hasMethod('allowAction') && in_array($action->id, $action->controller->allowAction())) {
  132. return false;
  133. }
  134. return true;
  135. }
  136. }