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:
parent
605ef09ed0
commit
ee036bd77d
3 changed files with 75 additions and 128 deletions
|
@ -104,40 +104,6 @@ Route::get('/callback', function () {
|
||||||
|
|
||||||
</Step>
|
</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">
|
<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.
|
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>
|
||||||
|
|
||||||
|
<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">
|
<Step title="Checkpoint: Test your application">
|
||||||
|
|
||||||
Now, you can test your application:
|
Now, you can test your application:
|
||||||
|
@ -174,35 +176,4 @@ Now, you can test your application:
|
||||||
|
|
||||||
</Step>
|
</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>
|
</Steps>
|
||||||
|
|
|
@ -6,6 +6,10 @@ const metadata: Readonly<GuideMetadata> = Object.freeze({
|
||||||
name: 'PHP',
|
name: 'PHP',
|
||||||
description: 'Integrate Logto into your PHP web app, such as Lavarel.',
|
description: 'Integrate Logto into your PHP web app, such as Lavarel.',
|
||||||
target: ApplicationType.Traditional,
|
target: ApplicationType.Traditional,
|
||||||
|
sample: {
|
||||||
|
repo: 'php',
|
||||||
|
path: 'samples',
|
||||||
|
},
|
||||||
fullTutorial: {
|
fullTutorial: {
|
||||||
title: 'Full PHP SDK tutorial',
|
title: 'Full PHP SDK tutorial',
|
||||||
url: 'https://docs.logto.io/sdk/php',
|
url: 'https://docs.logto.io/sdk/php',
|
||||||
|
|
|
@ -120,39 +120,6 @@ async def callback():
|
||||||
|
|
||||||
</Step>
|
</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">
|
<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.
|
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>
|
||||||
|
|
||||||
|
<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">
|
<Step title="Checkpoint: Test your application">
|
||||||
|
|
||||||
Now, you can test your application:
|
Now, you can test your application:
|
||||||
|
@ -192,34 +194,4 @@ Now, you can test your application:
|
||||||
|
|
||||||
</Step>
|
</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>
|
</Steps>
|
||||||
|
|
Loading…
Reference in a new issue