How get user data with Yii2 bearer authentication? - rest

I need to get the user data to use for the access control. I bearer authentication works fine, the user session is disabled.
public static function findIdentityByAccessToken ($token, $type = null) {
$user = static::findOne(['access_token' => $token, 'status' => self::STATUS_ACTIVE]);
if ( $user ) {
if ( $user->isAccessTokenValid() ) {
$user->last_request = time();
$user->save(false);
return $user;
}
}
return null;
}
The Yii::$app->user->id and Yii::$app->user->getId() return null because the session is disabled.
I need to use it in:
$behaviors['access'] = ['class' => AccessControl::class,
'only' => ['view'],
'rules' => [
[
'actions' => ['view'],
'allow' => false,
'roles' => User::isUserAdmin(Yii::$app->user->getId()),
],
[
'actions' => ['view'],
'allow' => true,
'roles' => User::isUserManager(Yii::$app->user->getId()),
],
],
];
I tried to save the user data or the token in public static variable in the user class, but the variable always null.

Related

Yii2 redirecting postman request to a different route in the api rest

I am accessing a route by the postman in an api made in Yii2, but the code that I insert in the action that corresponds to that route is not working. Follow the request print:
postman-request-print
The request return was not meant to be the one in the image, because the code I put in the 'create' action was this:
<?php
namespace app\modules\api\controllers;
use Yii;
use app\modules\pesquisa_mercado\models\PontoDaPesquisa;
class PesquisaPontoController extends \yii\rest\ActiveController
{
public $modelClass = 'app\modules\pesquisa_mercado\models\PesquisaPonto';
public function behaviors()
{
$behaviors = parent::behaviors();
return $behaviors + [
[
'class' => \yii\filters\auth\HttpBearerAuth::className(),
'except' => ['options'],
],
'verbs' => [
'class' => \app\modules\api\behaviors\Verbcheck::className(),
'actions' => [
'index' => ['GET'],
'create' => ['POST'],
'update' => ['PUT'],
'view' => ['GET'],
'delete' => ['DELETE'],
'finalizar-pesquisa' => ['POST'],
],
],
];
}
public function actions()
{
$actions = parent::actions();
unset($actions['update']);
return $actions;
}
public function actionCreate()
{
die("Test"); // test inserted here
}
}
That is, the return was to be 'Test'. For some reason I don't know, the route is being redirected to another place.
I also discovered that the request goes through the getLinks () method present in the PesquisaPonto model:
<?php
namespace app\modules\pesquisa_mercado\models;
class PesquisaPonto extends \yii\db\ActiveRecord implements \yii\web\Linkable
{
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%pesquisa_ponto}}';
}
/**
* #inheritdoc
*/
public function getLinks() // the requisition also passes through here!
{
return [
Link::REL_SELF => Url::to(['pesquisa-ponto/view', 'id' => $this->id], true),
'index' => Url::to(['pesquisa-ponto'], true)
];
}
}
Also follow the configuration of urlManager:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => true,
'rules' => [
// Pontos de Pesquisa
// api/pesquisa-ponto
[
'class' => 'yii\rest\UrlRule',
'controller' => [
'api/pesquisa-ponto'
],
'pluralize' => false,
],
],
]
I still haven't found the reason why Yii2 is redirecting the route and not allowing the postman to access the 'create' action...
The actions() method in yii\rest\ActiveController looks like this
public function actions()
{
return [
// ...
'create' => [
'class' => 'yii\rest\CreateAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->createScenario,
],
// ...
];
}
In your implementation of actions() method you are only removing the configuration for update action but the configuration for create action is left untouched. That means that the action is run from the yii\rest\CreateAction not the actionCreate() method of the controller.
To run the action from the PesquisaPontoController::actionCreate() you have to unset the configuration for the create action as well.
public function actions()
{
$actions = parent::actions();
unset($actions['update'], $actions['create']);
return $actions;
}

Queue is created but never executed

I'm trying to trigger push notifications and emails in the background of my Lumen API. I created the WarningUser class that creates both queues:
<?php
namespace App\Utils;
use App\Jobs\ProcessNotification;
use App\Mail\AllMail;
use Illuminate\Support\Facades\Mail;
class WarningUser
{
public static function send($user, $message, $url, $data = [])
{
$url = env('APP_URL_FRONT') . $url;
dispatch(new ProcessNotification($user, $data, $message, $url));
$emailData = EmailTexts::texts('pt', $data)[$message];
Mail::to($user->email)->queue(new AllMail($emailData['title'], $emailData['content']));
return true;
}
}
First we have the ProcessNotification job, which connects to Firebase and sends the notification:
<?php
namespace App\Jobs;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\Notification;
use Kreait\Firebase\Messaging\CloudMessage;
class ProcessNotification extends Job
{
protected $user = null;
protected $data = null;
protected $message = null;
protected $url = null;
public function __construct($user, $data, $message, $url)
{
$this->user = $user;
$this->data = $data;
$this->message = $message;
$this->url = $url;
}
public function handle()
{
if (\is_string($this->user->token) and $this->user->token !== '') {
$messaging = (new Factory())
->withServiceAccount(__DIR__.'/../../private-key.json')
->createMessaging();
$notificationData = NotificationTexts::texts('pt', $this->data)[$this->message];
$messageAlert = CloudMessage::withTarget('token', $this->user->token)
->withNotification(Notification::create($notificationData['title'], $notificationData['content']))
->withData([ 'url' => $this->url ]);
$messaging->send($messageAlert);
}
}
}
And finally AllMail that sends a simple email:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class AllMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
protected $title;
protected $body;
public function __construct($title, $body)
{
$this->title = $title;
$this->body = $body;
}
public function build()
{
return $this
->subject($this->title)
->view('email')
->with([
'title' => $this->title,
'body' => $this->body
]);
}
}
I've tested both codes without using queues, and they work, but when I put the queue it stops working. The processes are recorded in my database (mongodb):
But the queue is never processed, I tried to execute php artisan queue: work andphp artisan queue: listen, but neither case works.
The queue is never attempted to be processed, nor does it go to the failed_jobs table
My config / queue.php is as follows. And my .env is with QUEUE_CONNECTION = database
<?php
return [
'default' => env('QUEUE_CONNECTION', 'database'),
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'your-queue-name'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
'database' => env('DB_CONNECTION', 'mongodb'),
'table' => 'failed_jobs',
],
];
Can someone help me? I no longer know what the error may be.
PS: At no time is a browser or console error displayed
I managed to solve, for Mongo we need to use some more settings:
The connection in queue.php must be:
'connections' => [
'database' => [
'driver' => 'mongodb',
'table' => 'jobs',
'queue' => 'default',
'expire' => 60,
],
...
And we need to register the package provider that works with mongo:
Jenssegers\Mongodb\MongodbQueueServiceProvider::class,

Magento 2 Plugins / Interceptors accessing and modifying $this object

I have a plugin that i want to modify functionality of a method within specific class in Magento 2 however am not quite sure on how to access the original object and return the modified data.
Original Method
protected function _initTotals()
{
$source = $this->getSource();
$this->_totals = [];
$this->_totals['subtotal'] = new \Magento\Framework\DataObject(
['code' => 'subtotal', 'value' => $source->getSubtotal(), 'label' => __('Subtotal')]
);
/**
* Add shipping
*/
if (!$source->getIsVirtual() && ((double)$source->getShippingAmount() || $source->getShippingDescription())) {
$this->_totals['shipping'] = new \Magento\Framework\DataObject(
[
'code' => 'shipping',
'field' => 'shipping_amount',
'value' => $this->getSource()->getShippingAmount(),
'label' => __('Shipping & Handling'),
]
);
}
/**
* Add discount
*/
if ((double)$this->getSource()->getDiscountAmount()) {
if ($this->getSource()->getDiscountDescription()) {
$discountLabel = __('Discount (%1)', $source->getDiscountDescription());
} else {
$discountLabel = __('Discount');
}
$this->_totals['discount'] = new \Magento\Framework\DataObject(
[
'code' => 'discount',
'field' => 'discount_amount',
'value' => $source->getDiscountAmount(),
'label' => $discountLabel,
]
);
}
$this->_totals['grand_total'] = new \Magento\Framework\DataObject(
[
'code' => 'grand_total',
'field' => 'grand_total',
'strong' => true,
'value' => $source->getGrandTotal(),
'label' => __('Grand Total'),
]
);
/**
* Base grandtotal
*/
if ($this->getOrder()->isCurrencyDifferent()) {
$this->_totals['base_grandtotal'] = new \Magento\Framework\DataObject(
[
'code' => 'base_grandtotal',
'value' => $this->getOrder()->formatBasePrice($source->getBaseGrandTotal()),
'label' => __('Grand Total to be Charged'),
'is_formated' => true,
]
);
}
return $this;
}
This i have set to have a plugin to modify functionality of method above with di.xml:
<type name="Magento\Sales\Block\Order\Totals">
<plugin disabled="false" name="Harrigo_EverDiscountLabel_Plugin_Magento_Sales_Block_Order_Totals" sortOrder="10" type="Harrigo\EverDiscountLabel\Plugin\Magento\Sales\Block\Order\Totals"/>
</type>
Plugin
class Totals
{
public function after_initTotals(
\Magento\Sales\Block\Order\Totals $subject,
$result
) {
if ((double)$subject->getSource()->getDiscountAmount() != 0 OR $subject->getSource()->getDiscountDescription() != null) {
if ($subject->getSource()->getDiscountDescription()) {
$discountLabel = __('Offer (%1)', $source->getDiscountDescription());
} else {
$discountLabel = __('Offer');
}
$subject->_totals['discount'] = new \Magento\Framework\DataObject(
[
'code' => 'discount',
'field' => 'discount_amount',
'value' => $source->getDiscountAmount(),
'label' => $discountLabel,
]
);
}
return $subject;
}
}
Have used $subject instead of $this within the plugin, this does not work for me however. How do I access the $this object within the plugin to add / overwrite $this->_totals['discount'] and return the updated $this object from within the plugin. I have it working fine with a standard preference but would rather use a plugin if possible.
I think you should check this before implementing above code.
http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html
As per devdocs for Magento2 protected functions can not be intercepted so We can not use plugins for that.
May be that is causing issue in your case.
Hope this helps!

How to differentiate oauth social media plugin in YII2

I have a website which using twitter, facebook or google to login to system.
I use oAuth and here is my code.
config
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => 'asdsad',
'clientSecret' => 'xzxas',
],
'twitter' => [
'class' => 'yii\authclient\clients\Twitter',
'consumerKey' => 'sadsd',
'consumerSecret' => 'dasdasd',
],
],
],
controller
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'oAuthSuccess'],
],
];
}
public function oAuthSuccess($client) {
// get user data from client
$userAttributes = $client->getUserAttributes();
echo '<pre>';
print_r($userAttributes);
die;
The question is how do i know that which one of social media the user use to log to system?
To differentiate your oauth client you can put some instance condition as:--
public function oAuthSuccess($client) {
$reponse = $client->getUserAttributes();
$session = Yii::$app->session;
$token = $client->accessToken->params['access_token'];
$session->set('token' ,$token);
$id = ArrayHelper::getValue($reponse , 'id');
$session->set('auth_id', $id);
//Facebook Oauth
if($client instanceof \yii\authclient\clients\Facebook){
//Do Facebook Login
}
//Google Oauth
elseif($client instanceof \yii\authclient\clients\GoogleOAuth){
//Do Google Login Condition
}
}
public function oAuthSuccess($client) {
// get user data from client
$userAttributes = $client->getUserAttributes();
if($client->getName() == 'twitter'){
........
}else if($client->getName() == 'facebook'){
.........
}

Basic Zend post workflow issue

I am new to this these technologies, so might not be asking to do this the easiest way, but: I want to create a form and ask for an ID value. Once submit is pressed, I want to take that ID, make an external XML call and then show the XML data. I am stuck on if I can do this in a single url:https://plesk.local:8443/modules/example/index.php/index/form. I would like to have both the form and the list data on the same page, so I can update the ID, press submit and see the new data...over and over...
I am trying to modify the basic "Example1" that Plesk includes. I can modify it and test it, but stuck on exactly how POST works. Ideally I want to have $this->view->form to have both a pm_Form_Simple and pm_View_List_Simple on the same $form view (if this makes sense).
So looking for help on
1) Can I use the same URL and handle the POST/GET from it
2) Can I have both a form and simple list on the same page?
thx!!!!!
Here is the sample controller:
<?php
class IndexController extends pm_Controller_Action
{
public function init()
{
parent::init();
// Init title for all actions
$this->view->pageTitle = 'Example Module';
// Init tabs for all actions
$this->view->tabs = array(
array(
'title' => 'Form',
'action' => 'form',
),
array(
'title' => 'List',
'action' => 'list',
),
);
}
public function indexAction()
{
// Default action will be formAction
$this->_forward('form');
}
public function formAction()
{
// Init form here
$form = new pm_Form_Simple();
$form->addElement('text', 'exampleText', array(
'label' => 'Example Text',
'value' => pm_Settings::get('exampleText'),
'required' => true,
'validators' => array(
array('NotEmpty', true),
),
));
$form->addControlButtons(array(
'cancelLink' => pm_Context::getModulesListUrl(),
));
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
// Form proccessing here
pm_Settings::set('exampleText', $form->getValue('exampleText'));
$this->_status->addMessage('info', 'Data was successfully saved.');
$this->_helper->json(array('redirect' => pm_Context::getBaseUrl()));
}
# NEW - start
if (0)
{
# I want to be back here after the POST
# Want to show the list here after I take the POST parameter and do an external XML call...
$list = $this->_getListRandom();
$this->view->list = $list;
}
# NEW - end
$this->view->form = $form;
}
public function listAction()
{
$list = $this->_getListRandom();
// List object for pm_View_Helper_RenderList
$this->view->list = $list;
}
public function listDataAction()
{
$list = $this->_getListRandom();
// Json data from pm_View_List_Simple
$this->_helper->json($list->fetchData());
}
private function _getListRandom()
{
$data = array();
#$iconPath = pm_Context::getBaseUrl() . 'images/icon_16.gif';
for ($i = 0; $i < 15; $i++) {
$data[] = array(
'column-1' => '' . (string)rand() . '',
'column-2' => (string)rand(),
);
}
$list = new pm_View_List_Simple($this->view, $this->_request);
$list->setData($data);
$list->setColumns(array(
'column-1' => array(
'title' => 'Random with link',
'noEscape' => true,
),
'column-2' => array(
'title' => 'Random with image',
'noEscape' => true,
),
));
// Take into account listDataAction corresponds to the URL /list-data/
$list->setDataUrl(array('action' => 'list-data'));
return $list;
}
}
Yes
Yes
I'm not expirienced in zend, so it just try, I suggest to replace formAction() with following code:
public function formAction()
{
// Init form here
$form = new pm_Form_Simple();
$form->addElement('text', 'exampleText', array(
'label' => 'Example Text',
'value' => pm_Settings::get('exampleText'),
'required' => true,
'validators' => array(
array('NotEmpty', true),
),
));
$form->addControlButtons(array(
'cancelLink' => pm_Context::getModulesListUrl(),
));
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
// Form proccessing here
pm_Settings::set('exampleText', $form->getValue('exampleText'));
$this->_status->addMessage('info', 'Data was successfully saved.');
$list = $this->_getListRandom();
$this->view->list = $list;
$this->view->form = $form;
// Redirects happens on next string, maybe you need to add something to getBaseUrl()
$this->_helper->json(array('redirect' => pm_Context::getBaseUrl()));
}
$this->view->form = $form;
}