Skip to content

Commit fd9897c

Browse files
Replace auth demo notes with something more up-to-date and practical
1 parent 57e0577 commit fd9897c

File tree

1 file changed

+81
-46
lines changed

1 file changed

+81
-46
lines changed

notes/speaker-notes.md

Lines changed: 81 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -167,54 +167,89 @@ This is a rough guide of what topics are best to introduce with each section.
167167

168168
- All security enforcement is on server. So what's the point of doing anything with auth in the client?
169169
- It's to provide a nice UX. Tell the user if they are logged in, and if so as who, and what features they may access.
170-
- Blazor has a set of APIs for talking about who a user is and affecting rendered UI based on that
171-
- The workshop code will use a cookie-based auth system whereby the login state is tracked by the server using a cookie.
172-
However there are other ways it can be done too:
173-
- Have the server issue a JWT on login to the client. Client stores it in localstorage and passes back to server
174-
as HTTP header on API calls. This is somewhat like OAuth with password flow, but has caveats.
175-
- Use OpenID Connect (OIDC) which is a protocol for logging in with an external identity provider and getting back
176-
an auth token that identifies you to other services. This is very flexible and pretty much industry standard for SPAs,
177-
and fixes the complicated problems inherent to cookie-based auth.
170+
- It's also about being able to log in a user and collect, hold, and send authentication tokens to the server in a robust and safe way.
171+
- The workshop code will use an OpenID Connect-based flow for acquiring tokens, which is built into Blazor WebAssembly's project templates. The user accounts will be stored in the server-side database. However, other options are also supported:
172+
- Instead of using your ASP.NET Core server as the OIDC provider, you can connect to an external OIDC-compliant login system such as AzureAD, Google login, etc.
173+
- (Note: OpenID Connect (OIDC) is a protocol for logging in with an external identity provider and getting back an auth token that identifies you to other services. This is very flexible and pretty much industry standard for SPAs, and fixes the complicated problems inherent to cookie-based auth.)
174+
- Instead of using OIDC, you can use the lower-level auth APIs to provide info about the user authentication state directly, based on whatever custom logic you have for determining who a user is logged in as
178175

179176
*demos*
180-
- Start with `BlazorWasmOidc` app but with `<LoginDisplay>` removed and `OidcClientAuthenticationStateProvider` DI service removed. Instead, have a `MyFakeAuthenticationStateProvider` hard-coded to return a logged-out state
181-
- See `MyFakeAuthenticationStateProvider` and explain it. Also, will replace with a better one shortly.
182-
- Imagine the server is going to reject weather forecast requests if you're logged out. Want to reflect that in the UI.
183-
- Add `[Authorize]` there and see it work
184-
- Might as well remove the menu entry if you're logged out - use <AuthorizeView> in `NavMenu.razor` to do that.
185-
- Now let's display the login state in the page header. Use `<AuthorizeView>` in `MainLayout.razor` to put that
186-
into the `top-row` element.
187-
- So that's how it behaves when logged out. Let's now simulate being logged in.
188-
- Modify MyFakeAuthenticationStateProvider to hard-code a particular username and a role.
189-
`new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "SomeUser"), new Claim(ClaimTypes.Role, "Admin"), }, "myfakeauth"));`
190-
- See it now reflected in UI
191-
- Lock things down to Admin role - see you can still access it
192-
- Remove user's Admin role - see you can no longer access it
193-
- Now let's integrate with an external OIDC auth flow
194-
- Replace DI service for `AuthenticationStateProvider` to use `OidcClientAuthenticationStateProvider`
195-
- In `MainLayout`, replace your auth display stuff with `<LoginDisplay>` component
196-
- Now log in via OIDC
197-
- Explain: this is just a quick and very simplistic integration with an OIDC flow. We're working on a production-grade
198-
one to ship in the box for the May release.
199-
- But is this really secure? What if the server tells the client that it's logged in as a specific user with certain claims,
200-
but the client misbehaves or is bypassed by the user, and made to act as if it's logged in as a different user or has
201-
different claims?
202-
- Not a problem. The malicious user may be able to trick their UI to display menu options they shouldn't have access
203-
to, but ultimately when they try to take an action against an external service, their auth token or cookie will be
204-
checked by that service, so they can't act as someone they aren't.
205-
206-
*demos-after: different kind of auth demo*
207-
- Show how you could do JWT-based auth with password flow (have UI in your app that asks for username/password,
208-
calls server which returns token, store it in localStorage, etc.)
209-
- Get MissionControl demo without `[Authorize]` on either client or server
210-
- See we can fetch the data without being logged in
211-
- Add `[Authorize]` on server and see it now fail
212-
- Add `[Authorize]` on client and see message saying to log in
213-
- See how `LoginDisplay` uses `<AuthorizeView>`
214-
- See how `LoginDialog` posts credentials to the server which returns a JWT token
215-
- See how `TokenAuthenticationStateProvider` parses the JWT and stores it in localStorage
216-
- See how logging out updates the UI immediately
217-
- Show OIDC flow
177+
- Start with a Blazor WebAssembly app into which you've:
178+
- Referenced the package `Microsoft.AspNetCore.Components.WebAssembly.Authentication`
179+
- In `_Imports.razor`, added `Microsoft.AspNetCore.Authorization` and `Microsoft.AspNetCore.Components.Authorization`
180+
- First you want to show the name of the logged in user. In `MainLayout.razor`, inside the top bar, add:
181+
182+
```razor
183+
<AuthorizeView>
184+
<Authorized>
185+
<strong>Hello, @context.User.Identity.Name!</strong>
186+
</Authorized>
187+
<NotAuthorized>
188+
You're not logged in. Please log in!
189+
</NotAuthorized>
190+
</AuthorizeView>
191+
```
192+
193+
- At first this gives an exception (no cascading auth state). Fix by adding `<CascadingAuthenticationState>` around everything in `App.razor`
194+
- Now you get a different exception about missing `AuthenticationStateProvider`.
195+
- This makes sense. How is the system supposed to know who the user is unless you tell it?
196+
- Now register a fake auth state provider in DI:
197+
198+
```cs
199+
class MyFakeAuthenticationStateProvider : AuthenticationStateProvider
200+
{
201+
public override Task<AuthenticationState> GetAuthenticationStateAsync()
202+
{
203+
// Hard-coded logged-out user
204+
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
205+
206+
return Task.FromResult(new AuthenticationState(claimsPrincipal));
207+
}
208+
}
209+
```
210+
211+
- Now the UI shows the user is logged out
212+
- Next want to limit access to `Counter.razor` to logged in users
213+
- Add `[Authorize]` there - see it has no effect
214+
- Fix by changing router to use `AuthorizeRouteView` - see it works now
215+
- Customize the `NotAuthorized` template
216+
- Next want to hide the counter link from nav menu if logged out
217+
- Do it using `<AuthorizeView>`
218+
- OK so that handles logged-out users. What happens if the user is logged in?
219+
- Change `MyFakeAuthenticationStateProvider` to have a hardcoded logged-in user:
220+
221+
```cs
222+
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] {
223+
new Claim(ClaimTypes.Name, "Bert"),
224+
//new Claim(ClaimTypes.Role, "superadmin")
225+
}, "fake"));
226+
```
227+
228+
- See the UI displays this. So far we've seen two ways to reflect auth state in the UI: `[Authorize]` and `<AuthorizeView>`. But what if you want to use auth state programmatically during logic?
229+
- Let's limit the counter to 3 except if you're a `superadmin`
230+
- Add UI to show this on counter page:
231+
232+
```razor
233+
<AuthorizeView Roles="superadmin">
234+
<Authorized>
235+
<p>You're a superadmin, so you can count as high as you like</p>
236+
</Authorized>
237+
<NotAuthorized>
238+
<p>You're a loser, so you can only count up to 3</p>
239+
</NotAuthorized>
240+
</AuthorizeView>
241+
```
242+
- Implement by adding `[CascadingParameter] public Task<AuthenticationState> AuthStateTask { get; set; }` and then inside the count logic, `await` it to get `authState` and then check `if (currentCount < 3 || authState.User.IsInRole("superadmin"))`
243+
- Summarize:
244+
- Three ways to interact with auth system
245+
- Various pieces working together behind the scenes to provide and update the auth state info
246+
- Although it looked messy to set it up in this demo, it's all set up for you by default in the project template. We only built it manually here so you could see the pieces step by step.
247+
- Now what about real auth, not the hardcoded auth state?
248+
- Create a new project: `dotnet new blazorwasm --hosted --auth Individual -o MyRealAuthApp`
249+
- Go through the UI flow of registering and logging in
250+
- See how the weather data is now protected on the server-side
251+
- See how we include the auth token with requests for it now
252+
- See in `Program.cs` how this is configured
218253

219254
## 07 JavaScript Interop
220255

0 commit comments

Comments
 (0)