Skip to content

Commit d997e84

Browse files
authored
Merge pull request #1047 from DuendeSoftware/bff-docs-cross-check
Update BFF docs (v3/v4 inconsistencies and undocumented functionality)
2 parents 206fc31 + 8381281 commit d997e84

15 files changed

Lines changed: 342 additions & 188 deletions

File tree

astro/src/content/docs/bff/extensibility/http-forwarder.md

Lines changed: 0 additions & 144 deletions
This file was deleted.
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
---
2+
title: "HTTP Forwarder"
3+
description: Learn how to customize the HTTP forwarding behavior in BFF by providing custom HTTP clients and request/response transformations
4+
date: 2020-09-10T08:22:12+02:00
5+
sidebar:
6+
order: 40
7+
redirect_from:
8+
- /bff/v2/extensibility/http_forwarder/
9+
- /bff/v3/extensibility/http_forwarder/
10+
- /identityserver/v5/bff/extensibility/proxy/
11+
- /identityserver/v6/bff/extensibility/http_forwarder/
12+
- /identityserver/v7/bff/extensibility/http_forwarder/
13+
---
14+
import { Tabs, TabItem } from "@astrojs/starlight/components";
15+
16+
You can customize the HTTP forwarder behavior in two ways
17+
18+
* provide a customized HTTP client for outgoing calls
19+
* provide custom request/response transformation
20+
21+
## Custom HTTP Clients
22+
23+
By default, Duende.BFF will create and cache an HTTP client per configured route or local path.
24+
25+
This invoker is set up like this:
26+
27+
```csharp
28+
var client = new HttpMessageInvoker(new SocketsHttpHandler
29+
{
30+
UseProxy = false,
31+
AllowAutoRedirect = false,
32+
AutomaticDecompression = DecompressionMethods.None,
33+
UseCookies = false
34+
});
35+
```
36+
37+
If you want to customize the HTTP client you can implement the `IForwarderHttpClientFactory` interface (from
38+
YARP's `Yarp.ReverseProxy.Forwarder` namespace), e.g.:
39+
40+
```csharp
41+
public class MyInvokerFactory : IForwarderHttpClientFactory
42+
{
43+
public HttpMessageInvoker CreateClient(ForwarderHttpClientContext context)
44+
{
45+
return new HttpMessageInvoker(new SocketsHttpHandler
46+
{
47+
// this API needs a proxy
48+
UseProxy = true,
49+
Proxy = new WebProxy("https://myproxy"),
50+
51+
AllowAutoRedirect = false,
52+
AutomaticDecompression = DecompressionMethods.None,
53+
UseCookies = false
54+
});
55+
}
56+
}
57+
```
58+
59+
...and override our registration:
60+
61+
```csharp
62+
services.AddSingleton<IForwarderHttpClientFactory, MyInvokerFactory>();
63+
```
64+
65+
## Custom Transformations When Using Direct Forwarding
66+
67+
The method `MapRemoteBffApiEndpoint` uses default transformations that:
68+
* removes the cookie header from the forwarded request
69+
* removes local path from the forwarded request
70+
* adds the access token to the original request
71+
72+
If you wish to change or extend this behavior, you can do this for a single mapped endpoint
73+
or for all mapped API endpoints.
74+
75+
### Changing The Transformer For A Single Mapped Endpoint
76+
77+
This code block shows an example of how you can extend the default transformers with an additional custom
78+
transform.
79+
80+
{/* prettier-ignore */}
81+
<Tabs syncKey="bffVersion">
82+
{/* prettier-ignore */}
83+
<TabItem label="Duende BFF v4">
84+
```csharp
85+
app.MapRemoteBffApiEndpoint("/local", new Uri("https://target/"), context => {
86+
87+
// If you want to extend the existing behavior, then you must call the default builder:
88+
DefaultBffYarpTransformerBuilders.DirectProxyWithAccessToken("/local", context);
89+
90+
// You can also add custom transformers, such as this one that adds an additional header
91+
context.AddRequestHeader("custom", "with value");
92+
93+
});
94+
```
95+
96+
The default transform builder performs these transforms:
97+
98+
```csharp
99+
context.AddRequestHeaderRemove("Cookie");
100+
context.AddPathRemovePrefix(pathMatch);
101+
context.AddBffAccessToken(pathMatch);
102+
```
103+
</TabItem>
104+
{/* prettier-ignore */}
105+
<TabItem label="Duende BFF v3">
106+
```csharp
107+
app.MapRemoteBffApiEndpoint("/local", "https://target/", context => {
108+
109+
// If you want to extend the existing behavior, then you must call the default builder:
110+
DefaultBffYarpTransformerBuilders.DirectProxyWithAccessToken("/local", context);
111+
112+
// You can also add custom transformers, such as this one that adds an additional header
113+
context.AddRequestHeader("custom", "with value");
114+
115+
});
116+
```
117+
118+
The default transform builder performs these transforms:
119+
120+
```csharp
121+
context.AddRequestHeaderRemove("Cookie");
122+
context.AddPathRemovePrefix(localPath);
123+
context.AddBffAccessToken(localPath);
124+
```
125+
</TabItem>
126+
</Tabs>
127+
128+
For more information, also see the [YARP documentation on transforms](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/yarp/transforms?view=aspnetcore-9.0)
129+
130+
### Changing The Default Transformer
131+
132+
You can change the default transformer builder delegate by registering one in the services collection:
133+
134+
{/* prettier-ignore */}
135+
<Tabs syncKey="bffVersion">
136+
{/* prettier-ignore */}
137+
<TabItem label="Duende BFF v4">
138+
```csharp
139+
BffYarpTransformBuilder builder = (pathMatch, context) => {
140+
141+
// If you want to extend the existing behavior, then you must call the default builder:
142+
DefaultBffYarpTransformerBuilders.DirectProxyWithAccessToken(pathMatch, context);
143+
144+
// You can also add custom transformers, such as this one that adds an additional header
145+
context.AddResponseHeader("added-by-custom-default-transform", "some-value");
146+
147+
};
148+
149+
services.AddSingleton<BffYarpTransformBuilder>(builder);
150+
```
151+
</TabItem>
152+
{/* prettier-ignore */}
153+
<TabItem label="Duende BFF v3">
154+
```csharp
155+
BffYarpTransformBuilder builder = (localPath, context) => {
156+
157+
// If you want to extend the existing behavior, then you must call the default builder:
158+
DefaultBffYarpTransformerBuilders.DirectProxyWithAccessToken(localPath, context);
159+
160+
// You can also add custom transformers, such as this one that adds an additional header
161+
context.AddResponseHeader("added-by-custom-default-transform", "some-value");
162+
163+
};
164+
165+
services.AddSingleton<BffYarpTransformBuilder>(builder);
166+
```
167+
</TabItem>
168+
</Tabs>
169+
170+
## Changing The Forwarder Request Configuration
171+
172+
:::note
173+
Forwarder request configuration is available in Duende BFF v4 and later.
174+
:::
175+
176+
You can also modify the forwarder request configuration, either globally or per mapped path.
177+
This can be useful if you want to tweak things like activity timeouts.
178+
179+
```csharp
180+
// Register a forwarder config globally:
181+
services.AddSingleton(new ForwarderRequestConfig()
182+
{
183+
ActivityTimeout = TimeSpan.FromMilliseconds(100)
184+
});
185+
186+
// Or modify one on a per mapped route basis:
187+
app.MapRemoteBffApiEndpoint("/local", new Uri("https://target/"),
188+
requestConfig: new ForwarderRequestConfig()
189+
{
190+
ActivityTimeout = TimeSpan.FromMilliseconds(100)
191+
});
192+
```

astro/src/content/docs/bff/extensibility/management/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ builder.Services.AddTransient<IDiagnosticsEndpoint, DefaultDiagnosticsEndpoint>(
4242
title="IBffEndpoint.cs"
4343
code={`public interface IBffEndpoint
4444
{
45-
Task ProcessRequestAsync(HttpContext context, CancellationToken ct);
45+
Task ProcessRequestAsync(HttpContext context, CancellationToken ct = default);
4646
}`}/>
4747

4848
You can customize the behavior of the endpoints by implementing the appropriate interface.

astro/src/content/docs/bff/extensibility/management/logout.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ The `IReturnUrlValidator` ensures that the `returnUrl` parameter passed to the l
2828
<Tabs syncKey="bffVersion">
2929
<TabItem label="V4">
3030
You can customize the behavior of the logout endpoint by implementing the `ProcessRequestAsync` method of the
31-
`ILogoutEndpoint` interface. The [default implementation][1]
31+
`ILogoutEndpoint` interface. The [default implementation](https://github.com/DuendeSoftware/products/tree/releases/bff/4.0.x/bff/src/Bff/Endpoints/Internal/DefaultLogoutEndpoint.cs)
3232
can serve as a starting point for your own implementation.
3333

3434
If you want to extend the default behavior of the logout endpoint, you can instead add a custom endpoint and
@@ -50,7 +50,7 @@ app.MapGet(bffOptions.LogoutPath, async (HttpContext context, CancellationToken
5050
`} />
5151
</TabItem>
5252
<TabItem label="V3">
53-
`ProcessRequestAsync` is the top-level function called in the endpoint service `DefaultSilentLoginCallbackService`,
53+
`ProcessRequestAsync` is the top-level function called in the endpoint service `DefaultLogoutService`,
5454
and can be used to add arbitrary logic to the endpoint.
5555

5656
For example, you could take whatever actions you need before normal processing of the request like this:
@@ -73,5 +73,3 @@ public override Task ProcessRequestAsync(HttpContext context, CancellationToken
7373
To prevent open redirector attacks, the `returnUrl` parameter to the logout endpoint must be validated. You can
7474
customize this validation by implementing the `IReturnUrlValidator` interface. The default implementation enforces
7575
that return URLs are local.
76-
77-
[1]: https://github.com/DuendeSoftware/products/tree/releases/bff/4.0.x/bff/src/Bff/Endpoints/Internal/DefaultLogoutEndpoint.cs

0 commit comments

Comments
 (0)