I'm a complete starter using laravel 5.1. I was a PHP developer by 3 to 4 years and between those I was allways working with Java EE and I just came back to PHP environement and found a complete new list of frameworks.
After a little research, and using some surveys results, I found that Laravel is the ultimate one. Now I used Laragon to install it successfully and have my first fresh application running. I learning a little about how a route works and that's ok.
Now I need to use Sentinel 2.0 in order to apply the right roles/auth to my application and then add the socialize part.
So to do that, I need to know few things :
Is there any way to "completely" get rid of the Auth component beside removing the controller Auth folder and the route in routes.php ?
Is there any tutorial (as I can't find) telling how to REALLY include the sentinel means how to create a simple view with all what it needs (controller, vars, routes ....)
Thank you
Yes, you can. For example, this is my code for API rest with JWT and Sentinel. You can seed your database with Sentinel:
Create roles
Example EXA Role
$role = \Sentinel::getRoleRepository()->createModel()->create([
'name' => 'Example',
'slug' => 'EXA',
]);
$role->permissions = [
'servicio_dash' => true,
'servicio_widget' => true,
];
$role->save();
User Role USR
$role = \Sentinel::getRoleRepository()->createModel()->create([
'name' => 'User',
'slug' => 'USR',
]);
$role->permissions = [
'servicio_dash' => true,
'servicio_widget' =>false,
];
$role->save();
Create 50users and asignate EXA role(Using faker)
$usr_role = \Sentinel::findRoleBySlug('EXA');
factory(App\User::class, 50)->make()->each(function ($u) use ($usr_role) {
\Sentinel::registerAndActivate($u['attributes']);
});
Bonus Track: Factory example
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'email' => $faker->safeEmail,
'password' => 'p4ssw0rd',
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'recycle' => false,
'phone' => $faker->phoneNumber,
'alt_email' => $faker->email
];
});
Only one user
$yo = factory(App\User::class)->make(['email' => 'jpaniorte#openmailbox.org']);
\Sentinel::registerAndActivate($yo['attributes']);
$jperez = User::where('email', 'jpaniorte#openmailbox.org')->firstOrFail();
$epa_role->users()->attach($jperez);
Authenticate Controller for API REST
public function authenticateCredentials(Request $request)
{
$credentials = $request->only('email', 'password');
$user = \Sentinel::authenticate($credentials);
return response()->json($user);
}
Authenticate with token (use JWT) and sentinel
public function authenticate(Request $request)
{
// grab credentials from the request
$credentials = $request->only('email', 'password');
try {
// attempt to verify the credentials and create a token for the user
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// all good so return the token
return response()->json(compact('token'));
}
Note: For this, you need configure JWT options with custom Auth provider, you can find this here
In any controller
public function hasPermission($type)
{
//$sentinel = \Sentinel::findById(\JWTAuth::parseToken()->authenticate()->id); //->this is for a token
$sentinel = \Sentinel::findById(1); //if you now the id
if($sentinel->hasAccess([$type]))
return response()->json(true, 200);
//yout custom handle for noAccess here
}
Related
I’m creating middlewares in strapi
I have three models, company, profile, people, and I’m registering three middlewares,
For instance, the middleware for company is in:
src/api/company/middlewares/my-middleware, which is:
module.exports = (config, { strapi }) => {
return (context, next) => {
console.log("middleware of company”);
};
};
I register each middleware in ./config/middlewares.js as (I'm following strapi v4 documentation)
https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/required/middlewares.html
module.exports = [
"strapi::errors",
"strapi::security",
"strapi::cors",
"strapi::poweredBy",
"strapi::logger",
"strapi::query",
"strapi::body",
"strapi::session",
"strapi::favicon",
"strapi::public",
{
resolve: "./src/api/company/middlewares/my-middleware",
},
{
resolve: "./src/api/people/middlewares/my-middleware",
},
{
resolve: "./src/api/profile/middlewares/my-middleware",
},
];
No matter where I place these registrations, the outcome is the same
But now, if I call, from postman, http://localhost:1337/api/companies?populate=*, for example, the middleware is executed but I get an error saying that this address was not found,
If I comment out the middlewares registration, the error disappears but the middlewares are not executed
What could I be doing wrong?
Thanks in advance
It seems like you never call the next function.
module.exports = (config, { strapi }) => {
return (context, next) => {
console.log("middleware of company”);
next()
};
};
Keep in mind that if your middleware is async, you need to await next().
Iam new to SQS php SDK, Iam not able to override RedrivePolicy using setQueueAttributes method :(
json string is not accepted as an attribute and I cannot find any clear resources to help me.
Have a look at the below example code:
$queueUrl = "QUEUE_URL";
$client = new SqsClient([
'profile' => 'default',
'region' => 'us-west-2',
'version' => '2012-11-05'
]);
try {
$result = $client->setQueueAttributes(array(
'Attributes' => [
'ReceiveMessageWaitTimeSeconds' => 20
],
'QueueUrl' => $queueUrl, // REQUIRED
));
var_dump($result);
} catch (AwsException $e) {
// output error message if fails
error_log($e->getMessage());
}
Full code:
https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/php/example_code/sqs/LongPollingSetQueueAttributes.php
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'admin' => array(
'pattern' => '^/',
'form' => array(
'login_path' => '/login',
'check_path' => '/login_check',
'always_use_default_target_path' => true,
'default_target_path' => '/profile'
),
'logout' => true,
'anonymous' => true,
'users' => function () use ($app) {
return new \App\UserProvider($app['dbs']['mysql']);
},
),
),
'security.access_rules' => array(
array('^/profile', 'ROLE_USER')
)
));
In a Silex 2 application I have been able to authenticate a users credentials in the login_check, but then on redirect is the dreaded (for me) Runtime exception "ContextListener.php line 74 There is no user provider for user "Symfony\Component\Security\Core\User\User".
(my 'standard' User provider class)
class UserProvider implements UserProviderInterface {
private $conn;
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
public function loadUserByUsername($username)
{
// $app['monolog']->addInfo(sprintf("User '%s' registered.", $username));
$stmt = $this->conn->executeQuery('SELECT * FROM users_wet4 WHERE email = ?', array(strtolower($username)));
if (!$user = $stmt->fetch()) {
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
return new User($user['email'], $user['password'], explode(',', $user['roles']), true, true, true, true);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof \App\Security\User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'Symfony\Component\Security\Core\User\User';
}
}
I've searched across it seems every instance of this issue, and it looks like the most common resolution in a Symfony installation is configuring security to point to the custom user provider, but I have not seen any examples for silex differently than the way above:
'users' => function () use ($app) {
return new \App\UserProvider($app['dbs']['mysql']);
},
(I've seen this in a security.xml file for symfony, is this kind of provider config what is missing?)
providers:
main:
entity: { class: FredUtilisateurBundle:User, property: login }
Is there anyone who can help me with the logic of the 'no user provider' after being authenticated?
Ok solved it, problem was actually here:
if (!$user instanceof \App\Security\User) {
should have just been User.
if (!$user instanceof User) {
or whatever Custom User you might have created.
\App\MyUser
I am trying to add FitBit OAuth to my Yii2 app. I have successfully managed to setup other APIs, such as Google and Facebook - but these are using yii\authclient\clients. Here I am trying to write my own using yii\authclient\OAuth2. Here is the code I have:
<?php
namespace app\auth\clients;
class Fitbit extends \yii\authclient\OAuth2{
public $authUrl = 'https://www.fitbit.com/oauth2/authorize';
public $tokenUrl = 'https://api.fitbit.com/oauth2/token';
public $apiBaseUrl = 'https://api.fitbit.com';
public $scope = 'profile';
protected function initUserAttributes(){
return $this->api('/1/user', 'GET');
}
protected function defaultName(){
return 'fitbit';
}
protected function defaultTitle(){
return 'Fitbit';
}
}
Here is the configuration I have:
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'google' => [
'class' => 'yii\authclient\clients\Google',
'clientId' => 'ID',
'clientSecret' => 'SECRET',
],
'fitbit' => [
'class' => 'app\auth\clients\Fitbit',
'clientId' => 'ID',
'clientSecret' => 'SECRET',
],
But I am stumped, as this is the error I get:
{"errors":[{
"errorType":"invalid_request",
"message":"Authorization header required. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."
}],
"success":false}
Any help would be really appreciated. Thank you.
EDIT My current thinking is something along the lines of:
return $this->api('/1/user', 'GET', [], [
'WWW-Authenticate' => 'Authorization: Basic ' . base64_encode($this->client_id . ':' . $this->client_secret),
]);
But this still gives me the same error.
I found this topic and answer: Change layout in the controller of Zend Framework 2.0 :: Answer
I am trying to do this:
public function loginAction() {
if ($this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('zfcadmin');
}
$this->layout('layout/login');
return new ViewModel();
}
But it doesn't work.
Sure I have file MODULE_DIR/view/layout/login.phtml.
I tried to var_dump($this->layout()); before setting layout and after it and it shows, that layout is changed after $this->layout('layout/login'); line. But it is not.
How to set different layout in controller?
Also, why I don't get any messages if layout is changed? Why standart layout loaded, instead of error?
I think, I have to set up layout somewhere (like I set routes, for example). Possibly in config ['view_manager']['template_map'] by adding something like:
$config = array(
'view_manager' => array(
'template_path_stack' => array(
__DIR__ . '/../view'
),
'template_map' => array(
'layout/login' => __DIR__ . '/../view/layout/login.phtml',
),
),
);
— like said there:
Of course you need to define those layouts, too... just check
Application Modules module.config.php to see how to define a layout.
That didn't helped me :(
Update 1
Tried this:
public function loginAction() {
if ($this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('zfcadmin');
}
$layout = $this->layout();
$layout->setTemplate('layout/login');
return new ViewModel();
}
as #alex suggested. Doesn't work :'(. Same result without return new ViewModel(); line.
You review files by yourself:
AdminController.php (loginAction)
module.config.php (to be sure I added layout/login correctly
Update 2
I tried to debug as you suggest.
I updated __invoke functioN:
public function __invoke($template = null)
{
var_dump($template);
die();
if (null === $template) {
return $this->getViewModel();
}
return $this->setTemplate($template);
}
There are some cases:
With code, you suggested:
$layout = $this->layout();
$layout->setTemplate('layout/login');
it displays NULL. So method is called, but $template is null variable.
With code, from post, I had given in the start of my post:
$this->layout('layout/login');
return new ViewModel();
It shows string(12) "layout/login".
Without any code (so layout layout/admin loaded (default for ZfcAdmin), it shows: string(12) "layout/admin".
If I load / of my site it page is loaded with standart layout (in both cases with or without layout/layout in module config.
Update 3
I tried this:
$layout = $this->layout();
var_dump($layout->getTemplate());
$layout->setTemplate('layout/login');
var_dump($layout->getTemplate());
die();
in controller. It shows: string(13) "layout/layout" string(12) "layout/login". So layout is changed. But standart layout layout/layout rendered instead of layout/login. :(
Because you're using ZfcAdmin and have the use_admin_layout option enabled in that module and the login route you're attempting to set a layout on is a child route of ZfcAdmin, the admin layout listener is kicking in and over-writing the template you're attempting to set in your controller action.
It's perhaps easiest to disable zfcadmin layout, write your own listener and handle the specific case of login layout there. You can do that using essentially the same method that ZfcAdmin uses in Module.php with a tweak or two ...
Be sure to disable ZfcAdmin layout
'zfcadmin' => array(
'use_admin_layout' => false,
),
then, using your module name as a config key, set up your own version of the same config ...
'myzfcadmin' => array(
'use_admin_layout' => true,
'admin_layout_template' => 'layout/admin',
// you could even define a login layout template here
'login_layout_template' => 'layout/login',
),
Next in MyZfcAdmin/Module.php add a listener, almost exactly like the one in ZfcAdmin only have it check your myzfcadmin config values instead ...
public function onBootstrap(MvcEvent $e)
{
$app = $e->getParam('application');
$em = $app->getEventManager();
$em->attach(MvcEvent::EVENT_DISPATCH, array($this, 'selectLayoutBasedOnRoute'));
}
public function selectLayoutBasedOnRoute(MvcEvent $e)
{
$app = $e->getParam('application');
$sm = $app->getServiceManager();
$config = $sm->get('config');
if (false === $config['myzfcadmin']['use_admin_layout']) {
return;
}
$match = $e->getRouteMatch();
$controller = $e->getTarget();
if (!$match instanceof \Zend\Mvc\Router\RouteMatch
|| 0 !== strpos($match->getMatchedRouteName(), 'zfcadmin')
|| $controller->getEvent()->getResult()->terminate()
) {
return;
}
if ($controller instanceof \MyZfcAdmin\Controller\AdminController
&& $match->getParam('action') == 'login'
) {
// if you'd rather just set the layout in your controller action just return here
// return;
// otherwise, use the configured login layout ..
$layout = $config['myzfcadmin']['login_layout_template'];
} else {
$layout = $config['myzfcadmin']['admin_layout_template'];
}
$controller->layout($layout);
}
As you can see, I added code to check the controller is your specific AdminController instance and login action, and if so, set the alternate template otherwise use the default, no need to worry about it in your controller now.
Add your layout in the template map of your view manager in the module.config.php
Like so:
// View file paths
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array
'layout/login' => 'path_to_layout_file'
)
)
Then, in your controller try setting the layout like this, using the setTemplate() method:
$layout = $this->layout();
$layout->setTemplate('layout/login');
EDIT, the following is code from the Zend library:
Inside Zend\Mvc\Controller\Plugin\Layout notice this method:
/**
* Invoke as a functor
*
* If no arguments are given, grabs the "root" or "layout" view model.
* Otherwise, attempts to set the template for that view model.
*
* #param null|string $template
* #return Model|Layout
*/
public function __invoke($template = null)
{
if (null === $template) {
return $this->getViewModel();
}
return $this->setTemplate($template);
}
If you don't provide a template it will call this method:
/**
* Retrieve the root view model from the event
*
* #return Model
* #throws Exception\DomainException
*/
protected function getViewModel()
{
$event = $this->getEvent();
$viewModel = $event->getViewModel();
echo '<pre>' . print_r($viewModel, true) . '</pre>';die;
if (!$viewModel instanceof Model) {
throw new Exception\DomainException('Layout plugin requires that event view model is populated');
}
return $viewModel;
}
Notice the print_r statement, if you look at it, it will show you this:
Zend\View\Model\ViewModel Object
(
[captureTo:protected] => content
[children:protected] => Array
(
)
[options:protected] => Array
(
)
[template:protected] => layout/layout
[terminate:protected] =>
[variables:protected] => Zend\View\Variables Object
(
[strictVars:protected] =>
[storage:ArrayObject:private] => Array
(
)
)
[append:protected] =>
)
Notice the [template:protected] => layout/layout that why I was saying I think Zend defaults to that layout.
So go into that file, in the __invoke method and do echo $template;die; when you are setting your layout with $this->setTemplate('layout/login') in your controller and see if its even getting passed there. Then you might be able to trace it better.
EDIT: Setting up multiple layouts.
Here is one way you could set up layouts for your modules in an effort to reduce the likelihood of a conflict or something being overwritten.
// where $sm is the service manager
$config = $sm->get('config');
$config = array_merge($config, include '/path_to_config/layouts.config.php');
if (isset($config['module_layouts'][$moduleNamespace]))
{
$controller->layout($config['module_layouts'][$moduleNamespace]);
}
And your layouts config could look something this:
'module_layouts' => array(
'_default' => 'layout/layout',
'admin' => 'layout/admin',
'foo' => 'layout/foo',
'login' => 'layout/login' // etc, etc
),