0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(console): php guide (#4351)

This commit is contained in:
Gao Sun 2023-08-17 11:40:08 +08:00 committed by GitHub
parent f0521fb36d
commit 0f98330455
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 211 additions and 5 deletions

View file

@ -1 +1,207 @@
## Replace this with actual guide
import UriInputField from '@/mdx-components-v2/UriInputField';
import Tabs from '@mdx/components/Tabs';
import TabItem from '@mdx/components/TabItem';
import InlineNotification from '@/ds-components/InlineNotification';
import { buildIdGenerator } from '@logto/shared/universal';
import Steps from '@/mdx-components-v2/Steps';
import Step from '@/mdx-components-v2/Step';
<Steps>
<Step title="Get started">
This tutorial will show you how to integrate Logto into your PHP web application.
<ul>
<li>The example uses Laravel, but the concepts are the same for other frameworks.</li>
<li>This tutorial assumes your website is hosted on <code>{props.sampleUrls.origin}</code>.</li>
</ul>
```bash
composer require logto/sdk
```
</Step>
<Step title="Init LogtoClient">
Insert the following code into your PHP file:
<pre>
<code className="language-php">
{`use logto\sdk\LogtoClient;
use Logto\Sdk\LogtoConfig;
$client = new LogtoClient(
new LogtoConfig(
endpoint: "${props.endpoint}",${props.alternativeEndpoint ? ' // or "${props.alternativeEndpoint}"' : ''}
appId: "${props.app.id}",
appSecret: "${props.app.secret}",
),
);`}
</code>
</pre>
By default, the SDK uses the built-in PHP session to store the Logto data. If you want to use other storage, you can pass a custom storage object as the second parameter:
```php
$client = new LogtoClient(
new LogtoConfig(
// ...
),
new YourCustomStorage(),
);
```
</Step>
<Step title="Implement the sign-in route">
<p>
First, lets enter your redirect URI. E.g. <code>{props.sampleUrls.callback}</code>. This is where Logto will redirect users after they sign in.
</p>
<UriInputField name="redirectUris" />
<pre>
<code className="language-php">
{`Route::get('/sign-in', function () {
return redirect($client->signIn('${props.redirectUris[0] || props.sampleUrls.callback}'));
});`}
</code>
</pre>
If you want to show the sign-up page on the first screen, you can set `interactionMode` to `signUp`:
<pre>
<code className="language-php">
{`Route::get('/sign-in', function () {
return redirect($client->signIn('${props.redirectUris[0] || props.sampleUrls.callback}', InteractionMode::signUp));
});`}
</code>
</pre>
Now, whenever your users visit `/sign-in`, it will start a new sign-in attempt and redirect the user to the Logto sign-in page.
> **Note**
> Creating a sign-in route isn't the only way to start a sign-in attempt. You can always use the `signIn` method to get the sign-in URL and redirect the user to it.
</Step>
<Step title="Implement the callback route">
After the user signs in, Logto will redirect the user to the callback URL you set in the Logto Console. In this example, we use `/callback` as the callback URL:
```php
Route::get('/callback', function () {
try {
$client->handleSignInCallback(); // Handle a lot of stuff
} catch (\Throwable $exception) {
return $exception; // Change this to your error handling logic
}
return redirect('/'); // Redirect the user to the home page after a successful sign-in
});
```
</Step>
<Step title="Implement the home page">
Here we implement a simple home page for demonstration:
- If the user is not signed in, show a sign-in button;
- If the user is signed in, show some basic information about the user.
```php
Route::get('/', function () {
if ($client->isAuthenticated() === false) {
return "Not authenticated <a href='/sign-in'>Sign in</a>";
}
return (
// Get local ID token claims
$client->getIdTokenClaims()->modelDumpJson(excludeUnset: true)
. "<br>"
// Fetch user info from Logto userinfo endpoint
$client->fetchUserInfo()->modelDumpJson(excludeUnset: true)
. "<br><a href='/sign-out'>Sign out</a>"
);
});
```
Our data models are based on [JsonModel](https://github.com/logto-io/php/blob/HEAD/docs/api/classes/Logto/Sdk/Models/JsonModel.md), which is safe to accept undefined keys while encoding or decoding JSON.
Note that a field (claim) with `null` value doesn't mean the field is set. The reason may be the related scope is not requested, or the user doesn't have the field.
For example, if we didn't request the `email` scope when signing in, and the `email` field will be `null`. However, if we requested the `email` scope, the `email` field will be the user's email address if available.
To learn more about scopes and claims, see [Scopes and claims](https://github.com/logto-io/php/blob/HEAD/docs/tutorial.md#scopes-and-claims).
</Step>
<Step title="Implement the sign-out route">
To clean up the Python session and Logto session, a sign-out route can be implemented as follows:
<pre>
<code className="language-python">
{`Route::get('/sign-out', function () {
return redirect(
// Redirect the user to the home page after a successful sign-out
$client->signOut('${props.sampleUrls.origin}')
);
});`}
</code>
</pre>
`postLogoutRedirectUri` is optional, and if not provided, the user will be redirected to a Logto default page after a successful sign-out (without redirecting back to your application).
> The name `postLogoutRedirectUri` is from the [OpenID Connect RP-Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html) specification. Although Logto uses "sign-out" instead of "logout", the concept is the same.
</Step>
<Step title="Checkpoint: Test your application">
Now, you can test your application:
<ol>
<li>Visit <code>{props.sampleUrls.origin}</code>, and you should see a "Not authenticated" message with a "Sign in" button.</li>
<li>Click the "Sign in" button, and you should be redirected to the Logto sign-in page.</li>
<li>After you sign in, you should be redirected back to <code>{props.sampleUrls.origin}</code>, and you should see your user info and a "Sign out" button.</li>
<li>Click the "Sign out" button, and you should be redirected back to <code>{props.sampleUrls.origin}</code>, and you should see a "Not authenticated" message with a "Sign in" button.</li>
</ol>
</Step>
<Step title="Protect your routes">
Now, you have a working sign-in flow, but your routes are still unprotected. Per the framework you use, you can create a middleware to protect your routes. For example, in Laravel, you can create a middleware as follows:
```php
namespace App\Http\Middleware;
use Closure;
class LogtoAuth
{
public function handle($request, Closure $next)
{
if ($client->isAuthenticated() === false) {
return redirect('/sign-in');
}
return $next($request);
}
}
```
Then, you can apply this middleware to your routes:
```php
Route::get('/protected', function () {
return "Protected page";
})->middleware(LogtoAuth::class);
```
</Step>
</Steps>

View file

@ -4,7 +4,7 @@ import { type GuideMetadata } from '../types';
const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'PHP',
description: 'PHP is the best language in the world.',
description: 'Integrate Logto into your PHP web app, such as Lavarel.',
target: ApplicationType.Traditional,
});

View file

@ -26,7 +26,7 @@ pip install logto # or `poetry add logto` or whatever you use
<Step title="Init LogtoClient">
Insert the following code into your python file:
Insert the following code into your Python file:
<pre>
<code className="language-python">
@ -34,7 +34,7 @@ Insert the following code into your python file:
client = LogtoClient(
LogtoConfig(
endpoint= "${props.endpoint}",${props.alternativeEndpoint ? ' // or "${props.alternativeEndpoint}"' : ''}
endpoint="${props.endpoint}",${props.alternativeEndpoint ? ' # or "${props.alternativeEndpoint}"' : ''}
appId="${props.app.id}",
appSecret="${props.app.secret}",
)
@ -152,7 +152,7 @@ Adding `exclude_unset=True` will exclude unset fields from the JSON output, whic
For example, if we didn't request the `email` scope when signing in, and the `email` field will be excluded from the JSON output. However, if we requested the `email` scope, but the user doesn't have an email address, the `email` field will be included in the JSON output with a `null` value.
To learn more about scopes and claims, see [Scopes and claims](https://github.com/logto-io/python/blob/master/docs/tutorial.md#scopes-and-claims).
To learn more about scopes and claims, see [Scopes and claims](https://github.com/logto-io/python/blob/HEAD/docs/tutorial.md#scopes-and-claims).
</Step>