mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor(console): update python and php guide (#6136)
* refactor(console): update python/php console guide * refactor(console): improve php guide * refactor(console): improve python guide --------- Co-authored-by: Gao Sun <gao@silverhand.io>
This commit is contained in:
parent
97b8201a57
commit
16be0f96a0
3 changed files with 170 additions and 125 deletions
|
@ -3,13 +3,17 @@ import UriInputField from '@/mdx-components/UriInputField';
|
||||||
|
|
||||||
import ExperienceOverview from './_experience-overview.md';
|
import ExperienceOverview from './_experience-overview.md';
|
||||||
|
|
||||||
|
export const defaultOrigin = 'http://localhost:3000/';
|
||||||
|
export const defaultCallbackUri = `${defaultOrigin}callback`;
|
||||||
|
export const defaultPostSignOutUri = defaultOrigin;
|
||||||
|
|
||||||
<ExperienceOverview />
|
<ExperienceOverview />
|
||||||
|
|
||||||
<InlineNotification>
|
<InlineNotification>
|
||||||
In the following steps, we assume your app is running on <code>http://localhost:3000</code>.
|
In the following steps, we assume your app is running on <code>{defaultOrigin}</code>.
|
||||||
</InlineNotification>
|
</InlineNotification>
|
||||||
|
|
||||||
Now, let's configure your redirect URI. E.g. {`${props.defaultUri ?? 'http://localhost:3000/callback'}`}.
|
Now, let's configure your redirect URI. E.g. {`${props.defaultUri ?? defaultCallbackUri}`}.
|
||||||
|
|
||||||
<UriInputField name="redirectUris" />
|
<UriInputField name="redirectUris" />
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import TabItem from '@mdx/components/TabItem';
|
||||||
import InlineNotification from '@/ds-components/InlineNotification';
|
import InlineNotification from '@/ds-components/InlineNotification';
|
||||||
import Steps from '@/mdx-components/Steps';
|
import Steps from '@/mdx-components/Steps';
|
||||||
import Step from '@/mdx-components/Step';
|
import Step from '@/mdx-components/Step';
|
||||||
|
import Checkpoint from '../../fragments/_checkpoint.md';
|
||||||
|
import RedirectUrisWeb, { defaultCallbackUri, defaultPostSignOutUri } from '../../fragments/_redirect-uris-web.mdx';
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
|
|
||||||
|
@ -11,10 +13,9 @@ import Step from '@/mdx-components/Step';
|
||||||
|
|
||||||
This tutorial will show you how to integrate Logto into your PHP web application.
|
This tutorial will show you how to integrate Logto into your PHP web application.
|
||||||
|
|
||||||
<ul>
|
<InlineNotification>
|
||||||
<li>The example uses Laravel, but the concepts are the same for other frameworks.</li>
|
The example uses Laravel, but the concepts are the same for other frameworks.
|
||||||
<li>This tutorial assumes your website is hosted on <code>{props.sampleUrls.origin}</code>.</li>
|
</InlineNotification>
|
||||||
</ul>
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
composer require logto/sdk
|
composer require logto/sdk
|
||||||
|
@ -26,7 +27,7 @@ composer require logto/sdk
|
||||||
|
|
||||||
Insert the following code into your PHP file:
|
Insert the following code into your PHP file:
|
||||||
|
|
||||||
<Code className="language-php">
|
<Code title="index.php" className="language-php">
|
||||||
{`use logto\sdk\LogtoClient;
|
{`use logto\sdk\LogtoClient;
|
||||||
use Logto\Sdk\LogtoConfig;
|
use Logto\Sdk\LogtoConfig;
|
||||||
|
|
||||||
|
@ -41,51 +42,28 @@ $client = new LogtoClient(
|
||||||
|
|
||||||
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:
|
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
|
<Code title="index.php" className="language-php">
|
||||||
$client = new LogtoClient(
|
{`$client = new LogtoClient(
|
||||||
new LogtoConfig(
|
new LogtoConfig(
|
||||||
// ...
|
// ...
|
||||||
),
|
),
|
||||||
new YourCustomStorage(),
|
new YourCustomStorage(),
|
||||||
);
|
);`}
|
||||||
```
|
</Code>
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step title="Implement the sign-in route">
|
<Step title="Implement the sign-in route">
|
||||||
|
|
||||||
<p>
|
<RedirectUrisWeb />
|
||||||
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" />
|
|
||||||
|
|
||||||
<Code className="language-php">
|
|
||||||
{`Route::get('/sign-in', function () {
|
|
||||||
return redirect($client->signIn('${props.redirectUris[0] || props.sampleUrls.callback}'));
|
|
||||||
});`}
|
|
||||||
</Code>
|
|
||||||
|
|
||||||
If you want to show the sign-up page on the first screen, you can set `interactionMode` to `signUp`:
|
|
||||||
|
|
||||||
<Code className="language-php">
|
|
||||||
{`Route::get('/sign-in', function () {
|
|
||||||
return redirect($client->signIn('${props.redirectUris[0] || props.sampleUrls.callback}', InteractionMode::signUp));
|
|
||||||
});`}
|
|
||||||
</Code>
|
|
||||||
|
|
||||||
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>
|
||||||
|
|
||||||
<Step title="Implement the callback route">
|
<Step title="Handle the callback">
|
||||||
|
|
||||||
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:
|
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
|
```php title="index.php"
|
||||||
Route::get('/callback', function () {
|
Route::get('/callback', function () {
|
||||||
try {
|
try {
|
||||||
$client->handleSignInCallback(); // Handle a lot of stuff
|
$client->handleSignInCallback(); // Handle a lot of stuff
|
||||||
|
@ -98,19 +76,38 @@ Route::get('/callback', function () {
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step title="Implement the sign-out route">
|
<Step title="Implement sign-in and sign-out">
|
||||||
|
|
||||||
|
There are various ways to invoke sign-in and sign-out in your application. For example, you can implement two routes in your PHP application:
|
||||||
|
|
||||||
|
<Code title="index.php" className="language-php">
|
||||||
|
{`Route::get('/sign-in', function () {
|
||||||
|
return redirect($client->signIn('${props.redirectUris[0] || defaultCallbackUri}'));
|
||||||
|
});`}
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
If you want to show the sign-up page on the first screen, you can set `interactionMode` to `signUp`:
|
||||||
|
|
||||||
|
<Code title="index.php" className="language-php">
|
||||||
|
{`Route::get('/sign-in', function () {
|
||||||
|
return redirect($client->signIn('${props.redirectUris[0] || defaultCallbackUri}', InteractionMode::signUp));
|
||||||
|
});`}
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
<UriInputField name="postLogoutRedirectUris" />
|
|
||||||
|
|
||||||
And a sign-out route can be implemented as follows:
|
And a sign-out route can be implemented as follows:
|
||||||
|
|
||||||
<Code className="language-php">
|
<Code title="index.php" className="language-php">
|
||||||
{`Route::get('/sign-out', function () {
|
{`Route::get('/sign-out', function () {
|
||||||
return redirect(
|
return redirect(
|
||||||
// Redirect the user to the home page after a successful sign-out
|
// Redirect the user to the home page after a successful sign-out
|
||||||
$client->signOut('${props.postLogoutRedirectUris[0] || props.sampleUrls.origin}')
|
$client->signOut('${props.postLogoutRedirectUris[0] || defaultPostSignOutUri}')
|
||||||
);
|
);
|
||||||
});`}
|
});`}
|
||||||
</Code>
|
</Code>
|
||||||
|
@ -128,7 +125,7 @@ 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 not signed in, show a sign-in button;
|
||||||
- If the user is signed in, show some basic information about the user.
|
- If the user is signed in, show some basic information about the user.
|
||||||
|
|
||||||
```php
|
```php title="index.php"
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
if ($client->isAuthenticated() === false) {
|
if ($client->isAuthenticated() === false) {
|
||||||
return "Not authenticated <a href='/sign-in'>Sign in</a>";
|
return "Not authenticated <a href='/sign-in'>Sign in</a>";
|
||||||
|
@ -157,14 +154,30 @@ To learn more about scopes and claims, see [Get user information](https://docs.l
|
||||||
|
|
||||||
<Step title="Checkpoint: Test your application">
|
<Step title="Checkpoint: Test your application">
|
||||||
|
|
||||||
Now, you can test your application:
|
<Checkpoint />
|
||||||
|
|
||||||
<ol>
|
</Step>
|
||||||
<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>
|
<Step title="Display user information">
|
||||||
<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>
|
To display the user's information, you can use either the `getIdTokenClaims` method or `fetchUserInfo` method to get user information. While `getIdTokenClaims` returns the user information contains in the ID token, `fetchUserInfo` fetches the user information from the userinfo endpoint.
|
||||||
</ol>
|
|
||||||
|
```php title="index.php"
|
||||||
|
Route::get('/userinfo', 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>"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import UriInputField from '@/mdx-components/UriInputField';
|
import UriInputField from '@/mdx-components/UriInputField';
|
||||||
import Steps from '@/mdx-components/Steps';
|
import Steps from '@/mdx-components/Steps';
|
||||||
import Step from '@/mdx-components/Step';
|
import Step from '@/mdx-components/Step';
|
||||||
|
import RedirectUrisWeb, { defaultCallbackUri, defaultPostSignOutUri } from '../../fragments/_redirect-uris-web.mdx';
|
||||||
|
import Checkpoint from '../../fragments/_checkpoint.md';
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
|
|
||||||
|
@ -10,7 +12,6 @@ This tutorial will show you how to integrate Logto into your Python web applicat
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>The example uses Flask, but the concepts are the same for other frameworks.</li>
|
<li>The example uses Flask, 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>
|
|
||||||
<li>Logto SDK leverages coroutines, remember to use <code>await</code> when calling async functions.</li>
|
<li>Logto SDK leverages coroutines, remember to use <code>await</code> when calling async functions.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ pip install logto # or `poetry add logto` or whatever you use
|
||||||
|
|
||||||
Insert the following code into your Python file:
|
Insert the following code into your Python file:
|
||||||
|
|
||||||
<Code className="language-python">
|
<Code title="main.py" className="language-python">
|
||||||
{`from logto import LogtoClient, LogtoConfig
|
{`from logto import LogtoClient, LogtoConfig
|
||||||
|
|
||||||
client = LogtoClient(
|
client = LogtoClient(
|
||||||
|
@ -38,8 +39,8 @@ client = LogtoClient(
|
||||||
|
|
||||||
Also replace the default memory storage with a persistent storage, for example:
|
Also replace the default memory storage with a persistent storage, for example:
|
||||||
|
|
||||||
```python
|
<Code title="main.py" className="language-python">
|
||||||
from logto import LogtoClient, LogtoConfig, Storage
|
{`from logto import LogtoClient, LogtoConfig, Storage
|
||||||
from flask import session
|
from flask import session
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
@ -56,50 +57,26 @@ class SessionStorage(Storage):
|
||||||
client = LogtoClient(
|
client = LogtoClient(
|
||||||
LogtoConfig(...),
|
LogtoConfig(...),
|
||||||
storage=SessionStorage(),
|
storage=SessionStorage(),
|
||||||
)
|
)`}
|
||||||
```
|
</Code>
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step title="Implement the sign-in route">
|
<Step
|
||||||
|
title="Configure redirect URIs"
|
||||||
|
subtitle="2 URIs"
|
||||||
|
>
|
||||||
|
|
||||||
<p>
|
<RedirectUrisWeb />
|
||||||
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" />
|
|
||||||
|
|
||||||
<Code className="language-python">
|
|
||||||
{`@app.route("/sign-in")
|
|
||||||
async def sign_in():
|
|
||||||
# Get the sign-in URL and redirect the user to it
|
|
||||||
return redirect(await client.signIn(
|
|
||||||
redirectUri="${props.redirectUris[0] || props.sampleUrls.callback}",
|
|
||||||
))`}
|
|
||||||
</Code>
|
|
||||||
|
|
||||||
If you want to show the sign-up page on the first screen, you can set `interactionMode` to `signUp`:
|
|
||||||
|
|
||||||
<Code className="language-python">
|
|
||||||
{`@app.route("/sign-in")
|
|
||||||
async def sign_in():
|
|
||||||
# Get the sign-in URL and redirect the user to it
|
|
||||||
return redirect(await client.signIn(
|
|
||||||
redirectUri="${props.redirectUris[0] || props.sampleUrls.callback}",
|
|
||||||
interactionMode="signUp", # Show the sign-up page on the first screen
|
|
||||||
))`}
|
|
||||||
</Code>
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step title="Implement the callback route">
|
<Step title="Handle the callback">
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
||||||
<Code className="language-python">
|
```python title="main.py"
|
||||||
{`@app.route("/callback")
|
@app.route("/callback")
|
||||||
async def callback():
|
async def callback():
|
||||||
try:
|
try:
|
||||||
await client.handleSignInCallback(request.url) # Handle a lot of stuff
|
await client.handleSignInCallback(request.url) # Handle a lot of stuff
|
||||||
|
@ -107,33 +84,51 @@ async def callback():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Change this to your error handling logic
|
# Change this to your error handling logic
|
||||||
return "Error: " + str(e)
|
return "Error: " + str(e)
|
||||||
`}
|
```
|
||||||
</Code>
|
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step title="Implement the sign-out route">
|
<Step title="Implement sign-in and sign-out">
|
||||||
|
|
||||||
|
There are various ways to invoke sign-in and sign-out in your application. For example, you can implement two routes in your Python application:
|
||||||
|
|
||||||
|
<Code title="main.py" className="language-python">
|
||||||
|
{`@app.route("/sign-in")
|
||||||
|
async def sign_in():
|
||||||
|
# Get the sign-in URL and redirect the user to it
|
||||||
|
return redirect(await client.signIn(
|
||||||
|
redirectUri="${props.redirectUris[0] || defaultCallbackUri}",
|
||||||
|
))`}
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
If you want to show the sign-up page on the first screen, you can set `interactionMode` to `signUp`:
|
||||||
|
|
||||||
|
<Code title="main.py" className="language-python">
|
||||||
|
{`@app.route("/sign-in")
|
||||||
|
async def sign_in():
|
||||||
|
# Get the sign-in URL and redirect the user to it
|
||||||
|
return redirect(await client.signIn(
|
||||||
|
redirectUri="${props.redirectUris[0] || defaultCallbackUri}",
|
||||||
|
interactionMode="signUp", # Show the sign-up page on the first screen
|
||||||
|
))`}
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
<UriInputField name="postLogoutRedirectUris" />
|
|
||||||
|
|
||||||
And a sign-out route can be implemented as follows:
|
And a sign-out route can be implemented as follows:
|
||||||
|
|
||||||
<Code className="language-python">
|
<Code title="main.py" className="language-python">
|
||||||
{`@app.route("/sign-out")
|
{`@app.route("/sign-out")
|
||||||
async def sign_out():
|
async def sign_out():
|
||||||
return redirect(
|
return redirect(
|
||||||
# Redirect the user to the home page after a successful sign-out
|
# Redirect the user to the home page after a successful sign-out
|
||||||
await client.signOut(postLogoutRedirectUri="${props.postLogoutRedirectUris[0] || props.sampleUrls.origin}")
|
await client.signOut(postLogoutRedirectUri="${props.postLogoutRedirectUris[0] || defaultPostSignOutUri}")
|
||||||
)
|
)
|
||||||
`}
|
`}
|
||||||
</Code>
|
</Code>
|
||||||
|
|
||||||
`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>
|
||||||
|
|
||||||
<Step title="Handle authentication status">
|
<Step title="Handle authentication status">
|
||||||
|
@ -145,43 +140,76 @@ 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 not signed in, show a sign-in button;
|
||||||
- If the user is signed in, show some basic information about the user.
|
- If the user is signed in, show some basic information about the user.
|
||||||
|
|
||||||
```python
|
```python title="main.py"
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
async def home():
|
async def home():
|
||||||
if client.isAuthenticated() is False:
|
if client.isAuthenticated() is False:
|
||||||
return "Not authenticated <a href='/sign-in'>Sign in</a>"
|
return "Not authenticated <a href='/sign-in'>Sign in</a>"
|
||||||
|
|
||||||
return (
|
return "Authenticated <a href='/sign-out'>Sign out</a>"
|
||||||
# Get local ID token claims
|
```
|
||||||
client.getIdTokenClaims().model_dump_json(exclude_unset=True)
|
|
||||||
+ "<br>"
|
</Step>
|
||||||
# Fetch user info from Logto userinfo endpoint
|
|
||||||
(await client.fetchUserInfo()).model_dump_json(exclude_unset=True)
|
<Step title="Checkpoint: Test your application">
|
||||||
+ "<br><a href='/sign-out'>Sign out</a>"
|
|
||||||
)
|
<Checkpoint />
|
||||||
|
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Display user information">
|
||||||
|
|
||||||
|
To display the user's information, you can use either the `getIdTokenClaims` method or `fetchUserInfo` method to get user information. While `getIdTokenClaims` returns the user information contains in the ID token, `fetchUserInfo` fetches the user information from the userinfo endpoint.
|
||||||
|
|
||||||
|
For example, you can implement an `@authenticated` decorator to protect the APIs from unauthorized access and store the user information in the Flask application context:
|
||||||
|
|
||||||
|
```python title="authenticated.py"
|
||||||
|
from functools import wraps
|
||||||
|
from flask import g, jsonify, redirect
|
||||||
|
from samples.client import client
|
||||||
|
|
||||||
|
def authenticated(shouldRedirect: bool = False, fetchUserInfo: bool = False):
|
||||||
|
def decorator(func):
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(*args, **kwargs):
|
||||||
|
if client.isAuthenticated() is False:
|
||||||
|
if shouldRedirect:
|
||||||
|
return redirect("/sign-in")
|
||||||
|
return jsonify({"error": "Not authenticated"}), 401
|
||||||
|
|
||||||
|
# Store user info in Flask application context
|
||||||
|
g.user = (
|
||||||
|
await client.fetchUserInfo()
|
||||||
|
if fetchUserInfo
|
||||||
|
else client.getIdTokenClaims()
|
||||||
|
)
|
||||||
|
return await func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's an API to show the user's information:
|
||||||
|
|
||||||
|
```python title="main.py"
|
||||||
|
@app.route("/protected/userinfo")
|
||||||
|
@authenticated(shouldRedirect=True, fetchUserInfo=True)
|
||||||
|
async def protectedUserinfo():
|
||||||
|
try:
|
||||||
|
return (
|
||||||
|
"<h2>User info</h2>"
|
||||||
|
+ g.user.model_dump_json(indent=2, exclude_unset=True).replace("\n", "<br>")
|
||||||
|
+ navigationHtml
|
||||||
|
)
|
||||||
|
except LogtoException as e:
|
||||||
|
return "<h2>Error</h2>" + str(e) + "<br>" + navigationHtml
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
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.
|
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/quick-starts/python/#get-user-information).
|
|
||||||
|
|
||||||
</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>
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
Loading…
Reference in a new issue