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:
parent
f0521fb36d
commit
0f98330455
3 changed files with 211 additions and 5 deletions
|
@ -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, let’s 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>
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue