Skip to content

Commit 1bf6d05

Browse files
committed
Do more updates based on the docs.
1 parent 92b23cd commit 1bf6d05

7 files changed

Lines changed: 205 additions & 98 deletions

File tree

‎src/Application.php‎

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414
*/
1515
namespace App;
1616

17+
use Authentication\AuthenticationService;
18+
use Authentication\AuthenticationServiceInterface;
19+
use Authentication\AuthenticationServiceProviderInterface;
20+
use Authentication\Middleware\AuthenticationMiddleware;
21+
use Authorization\AuthorizationService;
22+
use Authorization\AuthorizationServiceInterface;
23+
use Authorization\AuthorizationServiceProviderInterface;
24+
use Authorization\Middleware\AuthorizationMiddleware;
25+
use Authorization\Policy\OrmResolver;
26+
use Psr\Http\Message\ServerRequestInterface;
1727
use Cake\Core\Configure;
1828
use Cake\Error\Middleware\ErrorHandlerMiddleware;
1929
use Cake\Http\BaseApplication;
@@ -27,7 +37,56 @@
2737
* want to use in your application.
2838
*/
2939
class Application extends BaseApplication
40+
implements AuthenticationServiceProviderInterface,
41+
AuthorizationServiceProviderInterface
3042
{
43+
/**
44+
* Load all the application configuration and bootstrap logic.
45+
*
46+
* @return void
47+
*/
48+
public function bootstrap(): void
49+
{
50+
// Call parent to load bootstrap from files.
51+
parent::bootstrap();
52+
53+
if (PHP_SAPI === 'cli') {
54+
$this->bootstrapCli();
55+
}
56+
57+
/*
58+
* Only try to load DebugKit in development mode
59+
* Debug Kit should not be installed on a production system
60+
*/
61+
if (Configure::read('debug')) {
62+
$this->addPlugin('DebugKit');
63+
}
64+
$this->addPlugin('Authentication');
65+
$this->addPlugin('Authorization');
66+
67+
// Load more plugins here
68+
}
69+
70+
/**
71+
* Bootrapping for CLI application.
72+
*
73+
* That is when running commands.
74+
*
75+
* @return void
76+
*/
77+
protected function bootstrapCli(): void
78+
{
79+
try {
80+
$this->addPlugin('Bake');
81+
} catch (MissingPluginException $e) {
82+
// Do not halt if the plugin is missing
83+
}
84+
85+
$this->addPlugin('Migrations');
86+
87+
// Load more plugins here
88+
}
89+
3190
/**
3291
* Setup the middleware queue your application will use.
3392
*
@@ -48,14 +107,15 @@ public function middleware($middlewareQueue): \Cake\Http\MiddlewareQueue
48107
->add(new RoutingMiddleware($this))
49108

50109
// add Authentication after RoutingMiddleware
51-
->add(new \Authentication\Middleware\AuthenticationMiddleware($this->configAuth()));
110+
->add(new AuthenticationMiddleware($this))
52111

53-
return $middlewareQueue;
112+
// Add authorization **after** authentication
113+
->add(new AuthorizationMiddleware($this));
54114

55115
return $middlewareQueue;
56116
}
57117

58-
protected function configAuth(): AuthenticationService
118+
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
59119
{
60120
$authenticationService = new AuthenticationService([
61121
'unauthenticatedRedirect' => '/users/login',
@@ -83,4 +143,11 @@ protected function configAuth(): AuthenticationService
83143

84144
return $authenticationService;
85145
}
146+
147+
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
148+
{
149+
$resolver = new OrmResolver();
150+
151+
return new AuthorizationService($resolver);
152+
}
86153
}

‎src/Command/ConsoleCommand.php‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
6+
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
7+
*
8+
* Licensed under The MIT License
9+
* For full copyright and license information, please see the LICENSE.txt
10+
* Redistributions of files must retain the above copyright notice.
11+
*
12+
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
13+
* @link https://cakephp.org CakePHP(tm) Project
14+
* @since 3.0.0
15+
* @license https://opensource.org/licenses/mit-license.php MIT License
16+
*/
17+
namespace App\Command;
18+
19+
use Cake\Console\Arguments;
20+
use Cake\Console\Command;
21+
use Cake\Console\ConsoleIo;
22+
use Cake\Console\ConsoleOptionParser;
23+
use Cake\Log\Log;
24+
use Psy\Shell as PsyShell;
25+
26+
/**
27+
* Simple console wrapper around Psy\Shell.
28+
*/
29+
class ConsoleCommand extends Command
30+
{
31+
/**
32+
* Start the Command and interactive console.
33+
*
34+
* @param \Cake\Console\Arguments $args The command arguments.
35+
* @param \Cake\Console\ConsoleIo $io The console io
36+
* @return int|null|void The exit code or null for success
37+
*/
38+
public function execute(Arguments $args, ConsoleIo $io)
39+
{
40+
if (!class_exists('Psy\Shell')) {
41+
$io->err('<error>Unable to load Psy\Shell.</error>');
42+
$io->err('');
43+
$io->err('Make sure you have installed psysh as a dependency,');
44+
$io->err('and that Psy\Shell is registered in your autoloader.');
45+
$io->err('');
46+
$io->err('If you are using composer run');
47+
$io->err('');
48+
$io->err('<info>$ php composer.phar require --dev psy/psysh</info>');
49+
$io->err('');
50+
51+
return static::CODE_ERROR;
52+
}
53+
54+
$io->out("You can exit with <info>`CTRL-C`</info> or <info>`exit`</info>");
55+
$io->out('');
56+
57+
Log::drop('debug');
58+
Log::drop('error');
59+
$io->setLoggers(false);
60+
restore_error_handler();
61+
restore_exception_handler();
62+
63+
$psy = new PsyShell();
64+
$psy->run();
65+
}
66+
67+
/**
68+
* Display help for this console.
69+
*
70+
* @param \Cake\Console\ConsoleOptionParser $parser The parser to update
71+
* @return \Cake\Console\ConsoleOptionParser
72+
*/
73+
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
74+
{
75+
$parser->setDescription(
76+
'This shell provides a REPL that you can use to interact with ' .
77+
'your application in a command line designed to run PHP code. ' .
78+
'You can use it to run adhoc queries with your models, or ' .
79+
'explore the features of CakePHP and your application.' .
80+
"\n\n" .
81+
'You will need to have psysh installed for this Shell to work.'
82+
);
83+
84+
return $parser;
85+
}
86+
}

‎src/Controller/AppController.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public function initialize(): void
4242
parent::initialize();
4343
$this->loadComponent('RequestHandler');
4444
$this->loadComponent('Flash');
45-
$this->loadComponent('Authorization.Authorization');
4645
$this->loadComponent('Authentication.Authentication');
46+
$this->loadComponent('Authorization.Authorization');
4747
}
4848

4949
public function beforeFilter(EventInterface $event)

‎src/Controller/ArticlesController.php‎

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,30 @@
77

88
class ArticlesController extends AppController
99
{
10-
11-
public function initialize(): void
12-
{
13-
parent::initialize();
14-
15-
$this->loadComponent('Flash'); // Include the FlashComponent
16-
$this->loadComponent('Paginator'); // Include the FlashComponent
17-
18-
$this->Auth->allow(['tags']);
19-
}
20-
2110
public function index()
2211
{
12+
$this->Authorization->skipAuthorization();
2313
$articles = $this->Paginator->paginate($this->Articles->find());
2414
$this->set(compact('articles'));
2515
}
2616

2717
public function view($slug)
2818
{
19+
$this->Authorization->skipAuthorization();
2920
$article = $this->Articles->findBySlug($slug)->firstOrFail();
3021
$this->set(compact('article'));
3122
}
3223

3324
public function add()
3425
{
35-
$article = $this->Articles->newEntity();
26+
$article = $this->Articles->newEmptyEntity();
27+
$this->Authorization->authorize($article);
28+
3629
if ($this->request->is('post')) {
3730
$article = $this->Articles->patchEntity($article, $this->request->getData());
3831

3932
// Added: Set the user_id from the session.
40-
$article->user_id = $this->Auth->user('id');
33+
$article->user_id = $this->request->getAttribute('identity')->getIdentifier();
4134

4235
if ($this->Articles->save($article)) {
4336
$this->Flash->success(__('Your article has been saved.'));
@@ -54,6 +47,7 @@ public function edit($slug)
5447
->findBySlug($slug)
5548
->contain('Tags') // load associated Tags
5649
->firstOrFail();
50+
$this->Authorization->authorize($article);
5751

5852
if ($this->request->is(['post', 'put'])) {
5953
$this->Articles->patchEntity($article, $this->request->getData(), [
@@ -80,6 +74,8 @@ public function delete($slug)
8074
$this->request->allowMethod(['post', 'delete']);
8175

8276
$article = $this->Articles->findBySlug($slug)->firstOrFail();
77+
$this->Authorization->authorize($article);
78+
8379
if ($this->Articles->delete($article)) {
8480
$this->Flash->success(__('The {0} article has been deleted.', $article->title));
8581
return $this->redirect(['action' => 'index']);
@@ -88,6 +84,8 @@ public function delete($slug)
8884

8985
public function tags()
9086
{
87+
$this->Authorization->skipAuthorization();
88+
9189
// The 'pass' key is provided by CakePHP and contains all
9290
// the passed URL path segments in the request.
9391
$tags = $this->request->getParam('pass');

‎src/Controller/UsersController.php‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public function index()
3434
}
3535

3636
public function login() {
37+
$this->Authorization->skipAuthorization();
38+
3739
$this->request->allowMethod(['get', 'post']);
3840
$result = $this->Authentication->getResult();
3941
// regardless of POST or GET, redirect if user is logged in
@@ -55,6 +57,8 @@ public function login() {
5557

5658
public function logout()
5759
{
60+
$this->Authorization->skipAuthorization();
61+
5862
$result = $this->Authentication->getResult();
5963
// regardless of POST or GET, redirect if user is logged in
6064
if ($result->isValid()) {
@@ -87,6 +91,8 @@ public function view($id = null)
8791
*/
8892
public function add()
8993
{
94+
$this->Authorization->skipAuthorization();
95+
9096
$user = $this->Users->newEntity();
9197
if ($this->request->is('post')) {
9298
$user = $this->Users->patchEntity($user, $this->request->getData());

‎src/Policy/ArticlePolicy.php‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
namespace App\Policy;
3+
4+
use App\Model\Entity\Article;
5+
use Authorization\IdentityInterface;
6+
7+
class ArticlePolicy
8+
{
9+
public function canAdd(IdentityInterface $user, Article $article)
10+
{
11+
// All logged in users can create articles.
12+
return true;
13+
}
14+
15+
public function canEdit(IdentityInterface $user, Article $article)
16+
{
17+
// logged in users can edit their own articles.
18+
return $this->isAuthor($user, $article);
19+
}
20+
21+
public function canDelete(IdentityInterface $user, Article $article)
22+
{
23+
// logged in users can delete their own articles.
24+
return $this->isAuthor($user, $article);
25+
}
26+
27+
protected function isAuthor(IdentityInterface $user, Article $article)
28+
{
29+
return $article->user_id === $user->getIdentifier();
30+
}
31+
}

0 commit comments

Comments
 (0)