I'm trying to implement yii\authclient\AuthAction's successCallback.
My code looks like this:
public function actions()
{
return [
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'successCallback'],
],
];
}
/**
* #param \yii\authclient\ClientInterface $client
*/
public function successCallback($client)
{
$attributes = $client->getUserAttributes();
$externalUser = new AuthForm();
$externalUser->authProvider = $client->getName();
$externalUser->externalUserId = array_key_exists('id', $attributes) ? $attributes['id'] : null;
if ($externalUser->validate())
{
if ($externalUser->isRegistered())
{
$externalUser->login();
return $this->redirect(['private/index']);
}
else
{
Yii::$app->session->set( 'signup/authProvider', $externalUser->authProvider );
Yii::$app->session->set( 'signup/attributes' , $attributes );
return $this->redirect(['site/signup']);
}
}
}
How can I call successCallback? I want to call the auth method. But I am not able to do this?
Most likely this is working fine, but you did not permit for the action of auth to be accessed. Make sure you allow auth in your behaviours of your controller. Something like:
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors [ 'access' ] = [
'rules' => [
[
'actions' => [ 'auth' ],
'allow' => true,
],
],
];
return $behaviors;
}
It will run successCallback when Auth server response successful.
You must config authcollection (collection config of auth server)
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'google' => [
'class' => 'yii\authclient\clients\GoogleOpenId'
],
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => 'facebook_client_id',
'clientSecret' => 'facebook_client_secret',
],
// etc.
],
]
...
]
Default: Yii2 authclient support some openid, oauth, oauth2 provider:
[[\yii\authclient\clients\Facebook|Facebook]].
[[yii\authclient\clients\GitHub|GitHub]].
Google (via [[yii\authclient\clients\GoogleOpenId|OpenID]] and [[yii\authclient\clients\GoogleOAuth|OAuth]]).
[[yii\authclient\clients\LinkedIn|LinkedIn]].
[[yii\authclient\clients\Live|Microsoft Live]].
[[yii\authclient\clients\Twitter|Twitter]].
[[yii\authclient\clients\VKontakte|VKontakte]].
Yandex (via [[yii\authclient\clients\YandexOpenId|OpenID]] and [[yii\authclient\clients\YandexOAuth|OAuth]]).
There's ready to use [[yii\authclient\widgets\AuthChoice]] widget to use in views:
<?= yii\authclient\widgets\AuthChoice::widget([
'baseAuthUrl' => ['site/auth'],
'popupMode' => false,
]) ?>
For more infomation: https://github.com/yiisoft/yii2-authclient/tree/master/docs/guide
Goodluck and have fun!
Related
I got this error when I'm trying to transcribe a call:
Account isn't authorized to call this operation. Check your account perm
I think the bad property is DataAccessRoleArn, I tried to create new role on IAM console, but it does not work.
Here's the full PHP code:
<?php
require 'vendor/autoload.php';
use Aws\TranscribeService\TranscribeServiceClient;
$awsKey = "{awsKey}";
$awsSecretKey = "{awsSecretKey}";
$clientAWS = new TranscribeServiceClient([
'region' => 'eu-west-3',
'version' => 'latest',
'credentials' => [
'key' => $awsKey,
'secret' => $awsSecretKey
],
]);
$result = $clientAWS->startCallAnalyticsJob([
'CallAnalyticsJobName' => 'Transcript1', // REQUIRED
'ChannelDefinitions' => [
[
'ChannelId' => 0,
'ParticipantRole' => 'AGENT',
],
[
'ChannelId' => 1,
'ParticipantRole' => 'CUSTOMER',
]
],
'DataAccessRoleArn' => 'arn:aws:iam::{id}:role/AWSRole', // REQUIRED
'Media' => [ // REQUIRED
'MediaFileUri' => 's3://{bucketName}/2022/02/23/file.wav',
'RedactedMediaFileUri' => 's3://{bucketName}/2022/02/23/',
],
'Settings' => [
'ContentRedaction' => [
'RedactionOutput' => 'redacted', // REQUIRED
'RedactionType' => 'PII', // REQUIRED
],
],
]);
print_r($result);
Do you know how to fix role issue?
For fixing this issue, you have to:
Select a region compatible (in my case eu-central-1)
Create a new role with AmazonS3FullAccess policy (just for testing, adjust for security) and this trust entity:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "transcribe.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Attach AmazonTranscribeFullAccess and AmazonS3FullAccess policiy to your IAM user (just for testing, adjust for security)
I am using Yii authclient to use social login. I had set everything as it is defined in docs but when I try to login with google it does not call onAuthSuccess method. When I try to login it just redirects me to returnUrl but not authenticated.
Here is my code;
config/main.php
'authClientCollection' => [
'class' => \yii\authclient\Collection::class,
'clients' => [
'google' => [
'class' => \yii\authclient\clients\Google::class,
'clientId' => *********, //changed for issue purpose
'clientSecret' => *********, //changed for issue purpose
'returnUrl' => 'http://localhost/site/landing',
],
],
]
controllers/SiteController
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup', 'auth'],
'rules' => [
[
'actions' => ['signup', 'auth'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
'create-storyboard' => ['post'],
],
],
];
}
/**
* {#inheritdoc}
*/
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, 'onAuthSuccess'],
],
];
}
public function onAuthSuccess($client)
{
(new AuthHandler($client))->handle();
}
If you set returnUrl the user is from auth provider redirected directly to the url you've set in that property.
In your case the returnUrl says google, that it should redirect user to http://localhost/site/landing. But there is nothing in your site/landing action that would call the onAuthSuccess.
You need to let user come back to site/auth and redirect them after processing response from OAuth provider. To do that remove the returnUrl from config. That will make the authclient to use default return url which is the action that started the auth process.
Then modify your onAuthSuccess to redirect users to site/landing like this:
public function onAuthSuccess($client)
{
(new AuthHandler($client))->handle();
$this->redirect(['site/landing']);
}
I had solved the problem with the help from #Michal HynĨica. The problem was in my returnUrl which means with authentication url it must follow to authenticate rather the redirecting after authentication. So all I need to do was changing it to as below.
'returnUrl' => 'http://localhost/site/auth?authclient=google'
Also don't forget to add same returnUrl to your google console's redirect url.
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.
This is my controller.
public function actions()
{
return [
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'oAuthSuccess'],
],
];
}
public function oAuthSuccess($client) {
$name = explode(" ",$userAttributes['name']);
$existing_customer = Customer::find()
->where(['email' => $userAttributes['email']])
->orWhere(['id_facebook' => $userAttributes['id']])
->one();
if(empty($existing_customer)){
$customer = new Customer();
$customer->firstname = $name[0];
$customer->lastname = $name[1];
$customer->id_default_group = 3;
$customer->username = $userAttributes['id'].'#facebook.com';
$customer->id_facebook = $userAttributes['id'];
$customer->email = $userAttributes['email'];
$password = rand(0000, 9999);
$auth_key = Yii::$app->getSecurity()->generateRandomString();
$customer->auth_key = $auth_key;
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
$customer->password_hash = $hash;
$customer->activation_code = $password;
$customer->active =1;
if ($customer->save(false)) {
$customergroup = new CustomerGroup();
$customergroup->id_customer = $customer->id_customer;
$customergroup->id_group = $customer->id_default_group;
$customergroup->save(false);
Yii::$app->response->redirect(['advanced','email' => $customer->email]);
}
}
This is my main.php file.
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'authUrl' => 'https://www.facebook.com/dialog/oauth?display=popup',
'clientId' => '',
'clientSecret' => '',
'scope' => [
'email',
'user_birthday',
'user_location',
'user_hometown',
],
],
],
],
Actually I am doing registration in 2 process.
After user click on facebook button it returns to my second step in popup, But i need it in my site. How is it possible?
change your auth successCallBack in action function with the action you desire..
below a sample where successCallback check if the user is a guest if true call the action authenticate otherwise the action connect
/** #inheritdoc */
public function actions()
{
return [
'auth' => [
'class' => AuthAction::className(),
'successCallback' => \Yii::$app->user->isGuest
? [$this, 'authenticate']
: [$this, 'connect'],
]
];
}
After the facebook login you return in your code inside the oAuthSuccess function .. i think the popup you are looking for is inside this function and is called from this redirect. if you want somethings others change the bootom part of this function..
Yii::$app->response->redirect(['advanced','email' => $customer->email]);
I have the following InputFilter:
<?php
namespace Login\InputFilter;
use Zend\InputFilter\InputFilter;
/**
* Class Login
*
* #package Login\InputFilter
*/
class Login extends InputFilter
{
/**
* Construct
*/
public function __construct()
{
/**
* Password
*/
$this->add(
[
'name' => 'password',
'required' => true,
'filters' => [
[
'name' => 'stringtrim'
]
],
'validators' => [
[
'name' => 'stringlength',
'options' => [
'min' => '5',
'max' => '128'
],
'break_chain_on_failure' => true
],
[
'name' => 'regex',
'options' => [
'pattern' => '/^[^\\\' ]+$/'
],
'break_chain_on_failure' => true
]
]
]
);
}
/**
* Init
*/
public function init()
{
/**
* Employee ID
*/
$this->add(
[
'name' => 'employeeId',
'required' => true,
'filters' => [
[
'name' => 'stringtrim'
]
],
'validators' => [
[
'name' => 'stringlength',
'options' => [
'min' => '1',
'max' => '20'
],
'break_chain_on_failure' => true
],
[
'name' => 'digits',
'break_chain_on_failure' => true
],
[
'name' => 'Login\Validator\EmployeeId',
'break_chain_on_failure' => true
]
]
]
);
}
}
Attached to the employeeId is a custom validator I've created to check if the Employee ID actually exists in a database. It has a constructor for Doctrine Entity Manager. This works fine when testing via the web, so no worries there.
However now I would like to test via PHPUnit and I've created the following test:
<?php
namespace LoginTest\InputFilter;
use Login\InputFilter\Login;
/**
* Class LoginTest
*
* #package LoginTest\InputFilter
*/
class LoginTest extends \PHPUnit_Framework_TestCase
{
/**
* #var Login $inputFilter
*/
protected $inputFilter;
public function setUp()
{
$this->inputFilter = new Login();
$this->inputFilter->init();
parent::setUp();
}
public function testFormHasElements()
{
$inputs = $this->inputFilter->getInputs();
$this->assertArrayHasKey(
'employeeId',
$inputs
);
$this->assertArrayHasKey(
'password',
$inputs
);
}
}
When the test runs the following error is produced:
1) LoginTest\InputFilter\LoginTest::testFormHasElements
Argument 1 passed to Login\Validator\EmployeeId::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in /vhosts/admin-application/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php on line 180 and defined
I'm not certain how I can get passed this particular error. I assume I need to use Mockery but I'm not certain.
The validator has a Factory which supplies the Doctrine Entity Manager from the Service Locator.
I am still very new to PHPUnit but I've been trying to do my research before asking here.
Any ideas?
You're getting this error because you directly instantiate you input filter and it isn't then aware of your custom validator factory.
In real application InputFilter is using Zend\Validator\ValidatorPluginManager for getting validators from service manager.
I see two ways how to solve this problem:
1.) You can setup real service manager from application configuration, like it's described in documentation and then pull the input filter from service manager:
$inputFilter = Bootstrap::getServiceManager()->get(\Login\InputFilter\Login::class); // change the service name if you have another
This solution is good if you want to write some kind of integration tests.
2.) You can mock your custom validator and inject into ValidatorPluginManager in setup method:
protected function setUp()
{
$validator = $this->getMockBuilder(\Login\Validator\EmployeeId::class)->getMock();
$inputFilter = new Login();
$inputFilter->getFactory()
->getDefaultValidatorChain()
->getPluginManager()
->setService(\Login\Validator\EmployeeId::class, $validator);
$inputFilter->init();
$this->inputFilter = $inputFilter;
parent::setUp();
}
This solution is good if you want to write unit tests for Login input filter.