0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

chore(console): align PHP/Python guide structure with docs (#5420)

This commit is contained in:
Darcy Ye 2024-02-23 10:57:38 +08:00 committed by GitHub
parent 605ef09ed0
commit ee036bd77d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 75 additions and 128 deletions

View file

@ -104,40 +104,6 @@ Route::get('/callback', function () {
</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, we can designate a post sign-out redierct URI. This is where Logto will redirect users after they sign out.
@ -161,6 +127,42 @@ The post sign-out redierct URI is optional, and if not provided, the user will b
</Step>
<Step title="Handle authentication status">
In Logto SDK, we can use `$client->isAuthenticated()` to check the authentication status, if the user is signed in, the value will be true, otherwise, the value will be false.
We also need to implement a 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
json_decode($client->getIdTokenClaims())
. "<br>"
// Fetch user info from Logto userinfo endpoint
json_decode($client->fetchUserInfo())
. "<br><a href='/sign-out'>Sign out</a>"
);
});
```
Our data models are based on [JsonModel](https://github.com/logto-io/php/blob/master/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 [Get user information](https://docs.logto.io/sdk/php/#get-user-information).
</Step>
<Step title="Checkpoint: Test your application">
Now, you can test your application:
@ -174,35 +176,4 @@ Now, you can test your application:
</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

@ -6,6 +6,10 @@ const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'PHP',
description: 'Integrate Logto into your PHP web app, such as Lavarel.',
target: ApplicationType.Traditional,
sample: {
repo: 'php',
path: 'samples',
},
fullTutorial: {
title: 'Full PHP SDK tutorial',
url: 'https://docs.logto.io/sdk/php',

View file

@ -120,39 +120,6 @@ async def callback():
</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.
```python
@app.route("/")
async def home():
if client.isAuthenticated() is False:
return "Not authenticated <a href='/sign-in'>Sign in</a>"
return (
# Get local ID token claims
client.getIdTokenClaims().model_dump_json(exclude_unset=True)
+ "<br>"
# Fetch user info from Logto userinfo endpoint
(await client.fetchUserInfo()).model_dump_json(exclude_unset=True)
+ "<br><a href='/sign-out'>Sign out</a>"
)
```
Our data models are based on [pydantic](https://docs.pydantic.dev/), so you can use `model_dump_json` to dump the data model to JSON.
Adding `exclude_unset=True` will exclude unset fields from the JSON output, which makes the output more precise.
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/HEAD/docs/tutorial.md#scopes-and-claims).
</Step>
<Step title="Implement the sign-out route">
To clean up the Python session and Logto session, we can designate a post sign-out redierct URI. This is where Logto will redirect users after they sign out.
@ -179,6 +146,41 @@ async def sign_out():
</Step>
<Step title="Handle authentication status">
In Logto SDK, we can use `client.isAuthenticated()` to check the authentication status, if the user is signed in, the value will be true, otherwise, the value will be false.
Here we also 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.
```python
@app.route("/")
async def home():
if client.isAuthenticated() is False:
return "Not authenticated <a href='/sign-in'>Sign in</a>"
return (
# Get local ID token claims
client.getIdTokenClaims().model_dump_json(exclude_unset=True)
+ "<br>"
# Fetch user info from Logto userinfo endpoint
(await client.fetchUserInfo()).model_dump_json(exclude_unset=True)
+ "<br><a href='/sign-out'>Sign out</a>"
)
```
Our data models are based on [pydantic](https://docs.pydantic.dev/), so you can use `model_dump_json` to dump the data model to JSON.
Adding `exclude_unset=True` will exclude unset fields from the JSON output, which makes the output more precise.
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 [Get user information](https://docs.logto.io/sdk/python/#get-user-information).
</Step>
<Step title="Checkpoint: Test your application">
Now, you can test your application:
@ -192,34 +194,4 @@ Now, you can test your application:
</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 decorator such as `@authenticated` to protect your routes. For example:
```python
from functools import wraps
def authenticated(func):
@wraps(func)
async def wrapper(*args, **kwargs):
if client.isAuthenticated() is False:
return redirect("/sign-in") # Or directly call `client.signIn`
return await func(*args, **kwargs)
return wrapper
```
Then, you can use the decorator to protect your routes:
```python
@app.route("/protected")
@authenticated
async def protected():
return "Protected page"
```
You can also create a middleware to achieve the same goal.
</Step>
</Steps>