euromark 11 年之前
父节点
当前提交
038df3e0b3
共有 3 个文件被更改,包括 351 次插入1 次删除
  1. 1 1
      Test/Case/Lib/Utility/TimeLibTest.php
  2. 116 0
      docs/TinyAuth/RoleSetup.md
  3. 234 0
      docs/TinyAuth/TinyAuth.md

+ 1 - 1
Test/Case/Lib/Utility/TimeLibTest.php

@@ -825,7 +825,7 @@ class TimeLibTest extends MyCakeTestCase {
 	 */
 	public function testAgeByHoroscop() {
 		App::uses('ZodiacLib', 'Tools.Misc');
-		$this->skipIf(php_sapi_name() === 'cli', 'Fix these tests');
+		$this->skipIf(true, 'Fix these tests');
 
 		$is = TimeLib::ageByHoroscope(2000, ZodiacLib::SIGN_VIRGO);
 		// between xxxx-08-24 and xxxx-09-23 the latter, otherwise the first:

+ 116 - 0
docs/TinyAuth/RoleSetup.md

@@ -0,0 +1,116 @@
+## Role Setup for TinyAuth
+
+The CakePHP default basically is User belongsTo Role (1:N).
+This "single role" setup works for most of the apps.
+
+If you really need a "multi role" setup where users can have multiple roles at once, you need an extra pivot table (users_roles per convention) that contains the role information per user. The User model doesn't need a role_id field then. In both cases the Role model just contains information about a role, nothing else.
+
+The following expects that you have read and understood the [TinyAuth docs](TinyAuth.md).
+
+### Single role
+If you don't even want to maintain a Role model and roles table, something like this suffices:
+```php
+$config['Role'] = array(
+	'admin' => '1',
+	'moderator' => '2',
+	'user' => '3',
+);
+```
+
+The session data of a logged in user then needs to look something like this:
+```php
+'Auth' => [
+    'User' => [
+        'id' => '1'
+        'role_id' => '3'
+    ]
+]
+```
+This is pretty much CakePHP standard for a simple belongsTo relation from User to Role (the Role model data itself is not necessary here, as "role_id" contains all we need.
+
+See [cakefest.dereuromark.de](http://cakefest.dereuromark.de/) and the github code for a live example.
+Also don't forget to check the test cases for Tiny. The reveal a lot of insight.
+
+### Multi role
+You will basically have a User and a Role model, and a pivot table roles_users with (role_id, user_id).
+
+For your AppController setup, you want to contain the HABTM Role:
+```php
+'authenticate' => [
+    'Form' => [
+        'contain' => ['Role']
+    ]
+]
+```
+
+As you can see from the [test cases for Tiny](https://github.com/dereuromark/tools/blob/master/Test/Case/Controller/Component/Auth/TinyAuthorizeTest.php), upon login the Session should look like this:
+```php
+'Auth' => [
+    'User' => [
+        'id' => '1'
+        'Role' => [
+            [
+                'id' => '1',
+                'RoleUser' => []
+            ],
+            [
+                'id' => '3',
+                'RoleUser' => []
+            ]
+        ]
+    ]
+]
+```
+This is the default structure when working with basic HABTM relations.
+
+Of course, you can also use your own AuthComponent / login hook where you simply add all the user's role as flat list:
+```php
+'Auth' => [
+    'User' => [
+        'id' => '1'
+        'Role' => ['1', '3']
+    ]
+]
+```
+That would be accepted from TinyAuth, as well.
+
+I don't have an open source example for this, so I just copied out details from an existing app.
+
+
+### A note about role access inside code/templates
+Basic role based access to actions is nice. But sometimes you also need role based decisions inside controller actions or the view templates, helpers or elements.
+
+If you are using a Role model + roles table you should have a slug field in there so you can identify the user's role(s) in the code.
+These can then either be hard-coded in the config, or added to it at runtime (once, ideally cached).
+
+So in your code and using Auth class as described in the blog post, you can use them anywhere like this:
+```php
+if (Auth::hasRole(Configure::read('moderator'))) {
+    echo $moderatorLinks;
+}
+```
+
+If you are using configure instead of a Role model, this is even easier as you can replace the magic numbers from above with constants.
+
+So in your bootstrap you define the roles as this:
+```php
+define('ROLE_ADMIN', 1);
+define('ROLE_MODERATOR', 2);
+define('ROLE_USER', 3);
+```
+
+In your config they now look like this:
+```php
+$config['Role'] = array(
+	'admin' => ROLE_ADMIN,
+	'moderator' => ROLE_MODERATOR,
+	'user' => ROLE_USER,
+);
+```
+
+So in your code and using Auth class as described in the blog post, you can use them anywhere like this:
+```php
+if (Auth::hasRoles(array(ROLE_ADMIN, ROLE_MODERATOR)) {
+    echo $this->element('moderator_info_box');
+}
+```

+ 234 - 0
docs/TinyAuth/TinyAuth.md

@@ -0,0 +1,234 @@
+# TinyAuth
+The fast and easy way for user authorization in CakePHP 2.x applications.
+
+See [my blog article](http://www.dereuromark.de/2011/12/18/tinyauth-the-fastest-and-easiest-authorization-for-cake2/) for additional
+infos and a live demo.
+
+
+## Basic Features
+- Singe or multi role
+- DB (dynamic) or Configure based role definition
+- INI file (static) based access rights (controller-action/role setup)
+- Lightweight and incredibly fast
+
+### Use if
+- You want to have a fixed (static) number of roles, and assign users to roles to define what actions etc. they can reach.
+- You want to have all those role/action pairs out of the controller and in a single place (file). Keeps the controller lean.
+
+### Do NOT use if
+- You need *row-level* based access (allow/deny actions to specific users).
+- You want to dynamically adjust access rights via backend (or enhance it with a web GUI yourself).
+
+### Planned features (not yet available):
+- AuthShell for easy CLI access / setup
+- Web frontend to optionally allow dynamic access rights
+
+
+## Docs
+
+### Preparations
+Please make sure the Tools Plugin is properly loaded (see the plugin readme for details).
+If you plan on using prefixed routing (admin, ...), enable those in your core.php or bootstrap.php.
+
+I assume you already got the AuthComponent included in the $components array of your AppController.
+You probably also excluded all public views with sth like
+```php
+$this->Auth->allow('contact_form'); // in beforeFilter() of the specific controllers
+```
+This snippet (in the contact controller) makes Auth skip this action completely. The action will be accessible to everybody right away.
+
+This is especially important for your login/register actions:
+```php
+// UsersController
+public function beforeFilter() {
+	parent::beforeFilter();
+	$this->Auth->allow('login', 'logout', 'register', ...);
+}
+```
+Those actions should never trigger any Authorize module. All other actions then use our ACL to determine if access is granted or not.
+
+You probably got a Role model (User belongsTo Role / User hasAndBelongsToMany Role) attached to the User.
+This table needs at least a "name" and an "alias" slug field to function. See the test fixture for details.
+
+If you don't want this, use Configure to store your keys like so:
+```php
+// in your config.php if applicable or using Configure::write('Role', array(...))
+$config['Role'] = array(
+	// slug => identifier (unique magical number or maybe better a constant)
+	'superadmin' => 1,
+	'admin' => 2,
+	'moderator' => 3,
+	'helper' => 4,
+	'user' => 5,
+);
+```
+The Configure approach overwrites any Model/table one.
+
+You should at least have a `user` - and maybe an `admin` role - for it to make sense.
+The advantage here: At any time you can switch from Configure to a Role model + roles table and vice versa without having to change much.
+
+You must also have some kind of Authentication in your AppController:
+```php
+$this->Auth->authenticate = array('Form'); // Uses username and password for login
+```
+**Important:** At least one type of authentication is necessary for any `Authorize` module to be usable.
+
+So far so good. You can login/logout and once you are logged in browse all non-public pages.
+Even admin pages, of course. Thats where the TinyAuth class comes in.
+
+
+### TinyAuth
+First of all include it in your beforeFilter() method of the AppController:
+```php
+$this->Auth->authorize = array('Tools.Tiny');
+```
+Alternatively, you could pass it as component settings right away:
+```php
+public $components = [
+        ...
+        'Auth' => [
+            'loginRedirect' => ...,
+            'logoutRedirect' => ...,
+            'authenticate' => ['Form'],
+            'authorize' => ['Tools.Tiny']
+        ],
+];
+```
+
+Now create a file in /Config/ called acl.ini like so:
+```ini
+[Tools.Countries]
+* = superadmin ; this is a comment
+
+[Account]
+edit,change_pw = *
+
+[Activities]
+admin_index,admin_edit,admin_add,admin_delete = admin,superadmin
+index = *
+
+[Users]
+index,search = user
+* = moderator,admin
+```
+
+The format is normal PHP INI style. I already included all kind of examples. * is a placeholder for "any".
+The plugin prefix for controllers is not necessary as of now (maybe for Cake3 where the same controller name is allowed multiple times due to PHP5.3 namespaces).
+Comments in INI files start with ";".
+
+Explanations:
+
+- Superadmin can access all Countries actions of the Tools plugin
+- Account actions are accessible by all roles (and therefore logged in persons)
+- Activities can be modified by all admins and listed by all (logged in persons)
+- Users can search and list other users, but only moderators and admins have access to all other actions
+
+That's it. Really easy, isn't it?
+
+
+### Some details
+TinyAuth expects a Session Auth User like so:
+```php
+Auth.User.id
+Auth.User.role_id (belongsTo - role key directly in the users table)
+```
+or so:
+```php
+Auth.User.id
+Auth.User.Role (hasAndBelongsToMany - multi role array containing all role keys)
+```
+As you can see <strong>it can manage both single and multiple role setup</strong>.
+That's sth the core one lacks, as well.
+
+The current configuration is cached in the persistent folder by default. In development mode (debug > 0) it will be regenerated all the time, though. So remember that you have to manually clear your cache in productive mode for changes to take effect!
+
+For more insight into the different role setups see [this Wiki page](https://github.com/dereuromark/tools/wiki/Tiny-Auth-Role-setup).
+
+
+### Quicktips
+If you have a cleanly separated user/admin interface there is a way to allow all user actions to users right away;
+```php
+$this->Auth->authorize = array('Tools.Tiny' => array('allowUser' => true));
+```
+Only for admin views the authorization is required then.
+
+If you got a "superadmin" role and want it to access everything automatically, do this in the beforeFilter method of your AppController:
+```php
+$userRoles = $this->Session->read('Auth.User.Role');
+if ($userRoles && in_array(Configure::read('Role.superadmin'), $userRoles)) {
+	// Skip auth for this user entirely
+	$this->Auth->allow('*'); // cake2.x: `$this->Auth->allow();` without any argument!
+}
+```
+
+
+### What about login/register when already logged in
+
+That is something most are neither aware of, nor does the core offer a out-of-the-box solution.
+Fact is, once you are logged in it is total nonsense to have access again to login/register/lost_pwd actions.
+Here comes my little trick:
+```php
+// In your beforeFilter() method of the AppController for example (after Auth adapter config!)
+$allowed = array('Users' => array('login', 'lost_password', 'register'));
+if (!$this->Session->check('Auth.User.id')) {
+	return;
+}
+foreach ($allowed as $controller => $actions) {
+	if ($this->name === $controller && in_array($this->request->action, $actions)) {
+		// Flash message - you can use your own method here - or CakePHP's setFlash() - as well
+		$this->Common->flashMessage('The page you tried to access is not relevant if you are already logged in. Redirected to main page.', 'info');
+		return $this->redirect($this->Auth->loginRedirect);
+	}
+}
+```
+
+
+### Changes
+
+#### UPDATE 2012-01-10
+The auth model can now be anything you like. It doesn't have to be `Role` or `role_id`.
+The new cake2.x uses "groups" per default.
+You can easily adjust that now by passing <code>`aclModel` => 'Group'</code> or <code>`aclKey` => 'group_id'</code> to the Tiny class, for instance.
+
+#### UPDATE 2013-03-10
+Some will be happy to hear that the deeper "contained" Role array is now supported besides the flat array of role keys. This deep/verbose array of roles has been introduced in Cake2.2 with the new ["contain" param for Auth](https://github.com/cakephp/cakephp/pull/594). So it made sense to support this in TinyAuth. See the test case for details.
+
+#### UPDATE 2013-06-25
+A new option `allowAdmin` makes it now possible to use TinyAuth even with less configuration in some cases. `True` makes the admin role access any admin prefixed action and together with `allowUser` (allows all logged in users to allow non admin prefixed URLs) this can be used to set up a basic admin auth. No additional configuration required except for the `adminRole` config value which needs to be set to the corresponding integer value.
+Of, course, you can additionally allow further actions. But if you just need to quickly enable an admin backend, this could be the way to go.
+
+
+### Notes
+
+#### NOTE 2012-02-25
+It seems that especially new-beys seem to mix up the meaning of `*` in the ACL. Although it is already laid out in the above text I will try to make it more clear:
+This `any` placeholder for "roles" only refers to those users that are logged in. You must not declare your public actions this way!
+All those must be declared in your controller using `$this->Auth->allow()` (in earlier versions of cake `$this->Auth->allow('*')).
+
+The reason is that Authenticate comes before Authorize. So without Authentication (logged in) there will never be any Authorization (check on roles).
+
+#### NOTE 2013-02-12
+You can use this in conjunction with my [Auth class](https://github.com/dereuromark/tools/blob/master/Lib/Auth.php) for a quick way to check on the current user and its role(s) anywhere in your application:
+{code type=php}
+App::uses('Auth', 'Tools.Lib'); // In your bootstrap (after plugin is loaded)
+
+if (Auth::id()) {
+	$username = Auth::user('username');
+	// do sth
+}
+
+if (Auth::hasRole(Configure::read('moderator'))) { // if you used configure slugs
+	// do sth
+}
+
+if (Auth::hasRoles(array(ROLE_ADMIN, ROLE_MODERATOR)) { // if you used configure and constants instead of magic numbers
+	// do sth
+}
+{/code}
+See the inline class documentation or the test cases for details.
+
+#### Upcoming
+A shell to quickly modify the INI file (and batch-update for new controllers etc) should be ready some time soon.
+
+There might some day also the possibility to use some CRUD backend to manage the ACL (either via database or modifying the INI file).
+If someone wants to help, go for it.