yii2-discourse-sso
Discourse SSO for Yii2, (*1)
Currently this extension only really deals with logging in., (*2)
Installing and configuring is quite easy., (*3)
Make sure to follow this guide on Discourse and while setting up SSO, after getting the secret needed,
configure your application like so:, (*4)
'discourseSso' => [
'class' => 'sammaye\discourse\Sso',
'secret' => "Some super secret, super awesome dupa secret key"
],
That is this extension installed. Now you just need to learn how to use it., (*5)
Your extension is accessible via Yii::$app->discourseSso
. This is the location used throughout this readme., (*6)
The first step is to setup a action in your SiteController.php
to actually do the logic of signing in someone:, (*7)
public function actionDiscourseSso()
{
$request = Yii::$app->getRequest();
$sso = Yii::$app->discourseSso;
$payload = $request->get('sso');
$sig = $request->get('sig');
if(!($sso->validate($payload, $sig))){
// invaild, deny
throw new ForbiddenHttpException('Bad SSO request');
}
$nonce = $sso->getNonce($payload);
if(Yii::$app->getUser()->isGuest){
// We add session variable to track it after we log the user in so we can redirect them back
// This method works well with custom login methods like social networks
Yii::$app->getSession()->set('sso', ['sso' => $payload, 'sig' => $sig]);
return $this->redirect(['site/login']);
}else{
$user = Yii::$app->getuser()->getIdentity();
}
Yii::$app->getSession()->remove('sso');
// We send over the data
$userparams = [
"nonce" => $nonce,
"external_id" => (String)$user->_id,
"email" => $user->email,
// Optional - feel free to delete these two
"username" => $user->username,
"name" => $user->username,
//'avatar_url' => Url::to(['image/profile-image', 'id' => (String)$user->_id], 'http')
];
$q = $sso->buildLoginString($userparams);
/// We redirect back
header('Location: ' . Yii::getAlias('@discourse') . '/session/sso_login?' . $q);
}
and even though this goes 90% of the way it does not complete it. If you notice:, (*8)
Yii::$app->getSession()->set('sso', ['sso' => $payload, 'sig' => $sig]);
We load the sig
and payload
into session so we can tell if we came from single sign-on so we can redirect back. This means that in
our login functions (whether it be login()
or some social login) we need to change it to (as an example for login
):, (*9)
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
if($sso = Yii::$app->getSession()->get('sso')){
return $this->redirect([
'discourse-sso',
'sso' => $sso['sso'],
'sig' => $sso['sig']
]);
}
if($model->getUser()->profile_filled){
return $this->goBack();
}else{
return $this->redirect(['user/about-me']);
}
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
Notice the if($sso = Yii::$app->getSession()->get('sso')){
, that is where he magic happens, it detects our single sign-on and redirects back to our single sign-on function., (*10)
To customise this, just add:, (*11)
if($sso = Yii::$app->getSession()->get('sso')){
return $this->redirect([
'discourse-sso',
'sso' => $sso['sso'],
'sig' => $sso['sig']
]);
}
to the end of every authentication function you have., (*12)