.NET 5 Blazor WebAssembly Authentication Against an API- A TimCo Retail Manager Video

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to the timco retail manager course this course focuses on real-world application development in this video we'll be connecting our new blazer app to the api so that when a user logs in they'll be authenticated against our api and get access to protected data this is going to be a fairly dense lesson so be sure to follow along closely and do what i do now for those of you who are subscribers my patreon at the five dollar per month level or higher head on over to get today's source code so you can get a good copy to compare against what you do in this video that way if you have any bugs or issues you can compare it against my finished source code and see what the differences are you can also get last week's source code or last time source code and use that as a fresh starting point for working on this video that way you know that everything is in line with what i'm doing now if you're new to this project welcome if you're just interested in this topic i think this will give you a great real world introduction to the topic if you'd like to start the project from the beginning there's a link in the description to get the whole playlist from start now if you want offline access and access to a certificate completion at each phase and a whole bunch of other perks you can go to my website iamtimcory.com and get the phase one and phase two sections of this course there all right let's head on over to visual studio now we're going to focus today in this web apps folder on the portal which is our wpf webassembly pro i'm sorry it's our blazer webassembly project i was looking down here before it's our blazer webassembly project which means that it needs an api to connect to it can't directly access the data which is great that's fine because we happen to have an api well not happen to have we designed it this way we start off with our wpf user interface knowing we'd be adding other user interfaces and wanted to use the same business logic the same data access the same authentication all of that so we have the same system for our wpf project as for our blazer web assembly project now today's goal is to connect our portal to the api for authentication now i have broken this video apart into two parts the second part will be focused on actually creating the the login and log out pages and using the authentication but today we're going to set up the authentication so that it will connect to the api now the first step to do this is to add a couple of new get packages so under dependencies right click and say manage nuget packages you can also do this from the package manager console i just prefer to do it here so i can show you how to search for these and find them all right the first one is going to be microsoft i can spell it right dot asp.net core dot components dot webassembly dot authentication all right and because my font size is so large it kind of scrolls off the page and say off but it really is authentication notes and mouse over it you get the full name there so this is going to allow us to do authentication inside blazer web assembly now we created this project we could have checked the box that says include authentication we did not do that because i didn't want extra stuff coming in we had to take out so instead we're going to add in that system manually and do it step by step just what we need all right so let's hit install we accept the license agreement and once that's installed we're going to um go back here to browse we'll clear this out and we will say we also want blazered so blazer ed dot local storage which is right here there's a lot of stuff that chris provides for us but blazer.localstorage storage is a really great tool that allows us access to local storage in blazer applications you may say wait wait tim they just added.net 5 local storage access for blazer server that's the difference blazer web assembly doesn't have that library at least not yet but we do have blazer.localstorage which does provide us that access it's a fairly common tool to be using so let's install that it gives very quick and easy access to to our blazer local storage and local storage is going to allow us to write something to the user's uh storage on the client in their browser that will be stored even after they close their browser now it's not going to be stored forever because the browser will clear it out sometimes depending on how the user cleans up their computer for example if they use a cleaner or something like that that's one of the things that often goes fairly quickly is a delete local storage which means you can't rely on it being there so just note that it may be if they clean their local storage out this is gone that's okay we're not gonna store anything there that is critical we're just gonna store the token so they can stay logged in but if they clear it out they have to log in again so those are the two two nuget packages we need to add now let's add a new file now i'm going to create a folder under the portal and i'm going to call this authentication i'm going to put everything for authentication in here and the reason for this is because i like to when i'm looking for authentication stuff i have to find it all in one spot rather than having to hunt for oh was this bit over here this bit over there i like it all in one spot so i know where everything is authentication is complicated enough without having to also track down where everything is and keep track of where everything is so this is just my attempt at making things a little simpler for us the first thing i add is a new class where i call this our jwt parser now this class is one that has been kind of passed down from originally steve sanderson from microsoft he uh created this parser and then it's been tweaked a little bit since then and now we're gonna use it so this is one of those cases where a really smart person created something and we're kind of building on the shoulders of giants now a a jwt token um is a a standard format okay so we can parse that into the data it contains and we're going to do that because we know what roles and what claims a user has what their information is so we want to capture all that information out of the token so therefore we need to parse that token in order to find those claims so that we can say yes you're allowed to go into administrative area or no you're not okay so some of this stuff a little dense that's okay it's okay to say yeah i know what the code does per se but not why it does that that's okay some of this stuff is a is gonna be a little dense the key is in this particular case just take the whole class now i am not advocating you take the whole class and not understand what it does that's not a good practice but sometimes when you're first learning something it's okay to try it out just by typing it word for word letter for letter and get it to work and then playing around it and trying it again and again until things start to click and start to see why and sometimes part of that process is getting to work putting it in development not production putting a breakpoint in and watching what happens as you step through the code because that can be illuminating and that means you have to have the code written before you understand it so in this case it's okay write it get it to work put that breakpoint in follow what the code does watch what it does and learn don't stay ignorant don't just say it works so i don't touch it that's a bad place to be but you can use it in development test it try it out use that debugging process to help you learn what the code is doing let's start with private static byte array parse base 64 without padding we're going to pass in our base 64 information and inside here we're going to say switch on the base64 dot length and modulo 4 so it's going to divide it by 4 and see if it is um what the result is here where i have two cases that's what the leftover is sorry not the result the leftover so in case you're not familiar with with this right here what would be is if we said uh 4 divided by 2 the result would be 0 because 2 goes into 4 evenly there's nothing remain there's no remainder this will provide the remainder so if you said five divided by two the remainder would be one if you said um you know uh divided by three there may be two because there's three two left over okay that's what we're working with here there's two possibilities here case of two now we're gonna say base 64 plus equals the double equals at the end oops there we go and break and then we have case three the base 64 plus equals just an equals at the end not two equals so we're kind of evening it out all right and then return convert from from base64 string 64. all right so we're we're passing in this base64 item we're seeing we're dividing the length by four and seeing if what the leftover is if it's two then we add two equals to the end if it's three we add one equal at the end and then from there we convert that from base64 string to a byte array right so that's the first thing we need to do now from there we need to private static void extract roles from jwt a list of claims and notice add the system.security.claims to my list up here we'll call that claims and a dictionary of type string object for our key value pairs at the end of this let's unpin this for now see we got a little more space here it'll be a lot of stuff it takes up a lot of space here key value pairs dot try get value claim types dot roll out object rolls okay so what we're doing right here well we are taking the um we're pulling the key value pairs and looking for the role type in that list if it finds it then we're going to do is extract the roles so let's try get value to say okay here's the the thing to look up if you find it then out which means the uh it creates a new object in this case and it's gonna call roles and that roles if it exists will be pulled out from that list of claim pairs okay so if roles is not equal to no or is not no how about that using the newer syntax i i love this format i love the is not all right you can say not equals that's fine var parsed roles equals roles to string trim it up then trim the start for this character and trim the end for this character and split on a comma all right so we have parse all the roles the user has access to if parsed roles dot length is greater than one for each var parsed roles parser roll sorry in parsed roles there we go claim dot add claims there we go dot add new claim claim type types dot roll and parsed role at position zero whoops not that one parsed role trim and we're going to trim out the uh the quotes okay so if we find more than one roll for each roll we're gonna add this uh add the roll type to our claims and say they want to take this parsed roll they won't really found but take off the double or yeah double quotes okay now note that we're adding it to this list of claims that's been passed in so remember that when we pass in an object that is a a class instance like a list of claims is a list of t and that's an instantiated item so we pass that in we're passing in a reference to it kind of that we're passing in the address of the house or say okay here's the address for this data well we're kind of using that to say okay well i know where the address is let's just add information into the house we'll put information into the house we don't have to pass that back then that's just going to update that that house so that whoever is um passing information into this extract role from jwt they're gonna have access to that same location now it just they just have more claims okay so that's the um the if the length is greater than one now we're going to say else claims dot add new claim claim types role parsed roles at position zero there we go so we're going to add just the one roll if we only have one roll okay we have multiple we're going to add each we're going to trim at the end trim on both sides with the uh the quotes okay remove from the quotes now at the very end of this we're also going to say key value pairs right down here key value pairs dot remove claim types roll right so if we found that up here because we're in the is not null so we found it in this key value pair list remember this is another instantiated object therefore we're just we have the address to this location we're going to take out the role from that list that way we can ensure that it's not double processed okay so we've processed it we've extracted the claims and now you've removed that item from the list and you just add the claims list okay these are both setup methods for our kind of our real method public static i innumerable of type claim and we're going to say parse claims from jwt string jwt like so oh we should also make this um the class static as well so we're gonna parse the claims from the jwt so you pass in a jwt you get back an i innumerable of claim all right which get a whole bunch of claims so var claims equals new list of claim all right and we're going to say var payload equals jwt dot split on the dot and we're only going to take the item at the second position this was called the payload section so there is header information then there's a dot then there's payload information then there's a dot and then there is verification or validation information third so we're gonna take just the payload information the payload is what has all the data that we need from our jwt okay so we're gonna grab just the payload var json bytes equals parse base64 without padding payload all right so i grab the bytes the json bytes and then we're going to say var key value pairs equals json serializer and it should have yes using system.txt.json up here they added that for us so if it doesn't add up for you just add that using statement up there json serializer dot d serialize dictionary of type string object and pass in the json bytes okay so we're going to break down these bytes we're going to serialize them into the key value pairs once we do that we're going to say extract from jwt where i pass in our claims and our key value pairs remember though that this is doing actions on both of them claims dot add range key value pairs dot select let's say oops select kvp our arrow new claim kvp dot key and kvp dot value dot to string so we're doing here is we're adding any claims to our claims that are in the key value pairs but remember that at the very end of this if we found the roles we first extracted the role information and then removed that key value pair that way the roles aren't going to be in there twice because we also then added our roles to the claims roles are a little bit different in how they are sent across and so we need to make sure that we put them in properly as claims so therefore we did our manual parsing of those roles we add them to our list of claims and remove them from the key value pairs so now they're already in the list of claims they don't need to be added again but for everything else in the key value pairs list we're going to grab the key and the value going value dot to string and adding those as claims to the list so those are all our claims and we'll say return claims okay so you may be asking what are claims what what's the information about claims and why is it important well this is where i get information about the logged in user there can be a lot of things you can use for claims for but for us we've used claims specifically for the role information so that we know um what roles they have access to is it admin is it cashier is it um i think it's a user's another one i'm not positive but they also have other information like their email address and their first name i believe so we can't have other information pass through we don't pass a lot of information though through about our user we use a separate api call after the initial call to pass additional uh kind of information about the user metadata i guess you'd call it but that's not pertaining to security it's more first and last name and you can pass phone number or anything else we want in that separate call we don't have to add to the authentication system and put it into the token the token does have a limit in how big it can be now we could have a really large token we're not anywhere near using the space we have available to us for the token but i tend to only put in the token what we need for security and for everything else i have a separate call for that it's up to you if you want to do that or not and that's all we're going to do for the jwt parser this is a kind of a self-contained utility now that's going to take in the jwt and pass out the list of claims that's exactly what we need in order to process this information cleanly let's close this out go back to solution explorer we're going to add another im2 authentication i'm going to call this our off state provider and in here we're actually going to inherit from authentication state provider which notice is a asp.net core components authorization element so it's going to add a using statement at the top right there okay so it didn't add for you you'd have to manually add it right now we need to first of all create a constructor we'll take care of that um the the red squiggles in just a minute okay constructor we're gonna pass in http client notice another using statement there online 5 using system.net.http and we'll say call us httpclient and then we also want an i local storage service which is going to bring in another using statement for blazer.localstorage and that's now on line one using blazer.localstorage and we'll call this local storage and then what we're going to do is we will make sure we create our control dot create our our fields for http client and also local storage sounds good we also need to add one more element which is a private read-only authentication state and we'll call this anonymous we're going to use this to return a status of anonymous which means you're not logged in essentially we're going to use this in places where we don't know what the user is maybe the crimsons come back bad or you know we just don't know who they are we can return this authentication state of anonymous okay down here we're going to have a public override of the get authentication state async which is going to need to be public override async task of authentication state get over get authentication state async right take out the not implemented exception we're going to implement it far token equals await local storage dot get item async oops not string get item async there we go get item async and it's gonna string and the key is auth token now we can make this key where you want i am roughing this in right now okay i want to extract this into a some kind of string constant that we put somewhere i want to think with this a little bit but here's the deal we're going to write a lot of code today we're going to write a lot of code today and so we've already written a lot of code just the jwt parser is something that i'd probably want to test out and probably should create a a unit test and test it but we're going to write a lot of code and so instead of creating more code now and trying to do anything perfect what i'm going to do is get things in place and working and then come back through and optimize them because if you optimize them now which we could do but if you do and then you have any kind of problems with your code you don't know if the problem is the optimization or if it's the code itself so instead get something working then optimize that way if you optimize something you try it again and it breaks you know it's the optimization that broke it not the code itself okay so we're going to say if string is null or white space token then return anonymous okay so if that token is empty then return anonymous so we're looking at local storage for the auth token how do we know it's called auth token well that's what we made up okay that's where we're going to store our token is in the key auth token if it's not there then we're going to return the anonymous which means you're not logged in so when you call this get authentication state when you're asking for are you off on a kid we're going to look up in the local storage to find a token and if it's not found then you're not logged in now if it is found because that return is going to stop the method right there but if it is found then http client default header request headers dot authorization equals new authentication header value which that's under system.net let's take care of that my goodness then do a control dot to add a using there there we go new authentication value where i say bearer and pass in the token so we're going to say that we check the authentication state if they are authenticated we're going to add the token in as the bearer in the header return new authentication state new claims principle which we can again shorten so let's do that ctrl dot to add the using for system.security.claims claims principle new claims identity and inside here the j w t parser dot parse claim from jwt pass in the token and then comma i know it's going to scroll so let's scroll over here you can see it pass in jw t off type okay so that's the authentication type is going to be passing our our token so we're going to return the authentication state which is a new claims principle which is a new claims identity takes in a new claims identity which takes in the um two pieces which are the claims and then also what type of authentication it is so this is where we're parsing our token which returns a list of claims which is what the i enumerable claim is what it's expecting in the claims identity so we're saying hey here's a list of claims and by the way the type is jwt auth type that's the type of authentication it is so that creates a claimed identity the claims principle takes in a claims identity and then from there the authentication state takes in a claims principle confusing yet well yeah i get how it could be so let's um let's give us some space here so you have a little bit of hierarchy a little bit less scrolling to do that's our return which is going to be the uh authentication state for the user okay so that is the get authentication state async we now need to go down here and say public void notify user authentication pass in the token and we're gonna say var authenticated user equals new claims principle new in fact you know what let's just take from here down like so instead of typing it all out again there we go that's going to grab our claims principle which is our new authenticated user information and so now i can say var off state equals task dot from result new authentication state authenticated user notify authentication state changed and pass in the off state so we have an event here that's going to say okay we've changed the login status of the user maybe the user just logged in or they just logged out either way it's going to i'm sorry whenever we log in it's going to flag that hey somebody's logged in and here's the new authentication state and pass in that state so that we can read that and capture that information so that's the event we're going to trigger is notify authentication state changed whenever the state has changed there's another one though for logout public void notify user log out this will be a little bit easier to understand what i was doing var auth state equals task dot from results anonymous what does that mean you're logged out all right so notify of authentication state changed and there's the off state which is we're logged out so we want to notify someone that we are logged out we're going to pass in an anonymous object and we're going to say okay i want you to alert that this is the new state of the user which is logged out okay we're almost through the hard part all right this is complicated stuff if you were expecting me to boil it down and something really simple um i'm sorry okay this is about as simple as i can make it and i know it's not simple and i'd love to make it simpler the problem is that authentication is complex and you really in some ways you don't want to be too simple you want some complexity here because you want the um the options set right but at the same time yes we have a long way to go when it comes to authentication systems because this is too complex we need to boil us down a lot better and it is something i'm looking into uh working with some people on and that is creating a very simple system that we can connect that we know is going to work right and that is open source and that is discoverable at the same time it's takes a lot of complexity out because this is so complex that it's hard sometimes to not create mistakes because you don't quite know what everything's going on it takes a while to understand it and oftentimes the the the default action is well i got to work therefore let's move on and that's i understand that philosophy i understand that feeling that we just don't have time to keep going over this when it works but don't do that okay you need to spend some time understand the flow understand why it's doing what it's doing when it's calling these different things and what the purpose is because if you don't understand the flow you won't understand when you introduce a bug and you won't understand when you introduce a security flaw so pay attention to this stuff walk the process through we're going to finish this process up we're going to get it working and then next week we're going to add in a login screen a logout screen and start using this at that point i want you to start using your break points i want you to start walking through this process so you understand it maybe you just type and follow along but at that point the next lesson we do we get to work with the api you can see the process going i want you to step through that code because you need to understand this okay this is your application's security if you don't understand it how do you know notice no holes in the wall all right so that's my last stay in the soapbox at least for now um but let's move on um because now is time to create something that's probably a little more familiar with you and that is some models so we're gonna add a new folder called models and we're going to add a class let's call this one authentication user model and in here this is what the model we're going to use to log a user in this is the information we have to send to the api to say this user wants access well that's a email address and password so prop string email prop string password now i can be done there but let's go ahead and add a required and put a message that says something like um your email address is required and notice i also did add the using statement up here for system.componentmodel.data annotations and then require down here and the error message will be password is required all right so now we have a username and password that's all there is for the authentication user model that's going to be what we use during the authentication process to say okay this user has given us the credentials is that valid okay now we're gonna have a return as well so let's right click on models and say add new class or call this authenticated user model and we know we have two return types from or to return values from our api based upon testing string access token and string user name these are the two things that our um our api will send to us all right and we know that because we we've done before we've done in the wpf project in fact if we go here in our models i believe it's in here somewhere um we would authenticate user model there we go authenticated user um gets the access token username so same thing in our ap our library for our user interface which is jpf is what we're using in our interface for our blazer webassembly project could we share models yeah probably and that's probably one of the um improvements we make is to create a separate models project which is shared by more than one user interface project that makes sense because we're gonna use the same api to access the same stuff so yes yes we're gonna do that but again we're roughing this in we're getting this going we're not necessarily making it perfect on the first pass we'll get to that but let's do it one step at a time okay it's time to add to another thing to our authentication folder and this is going to be the authentication service this was going to do the actual work of logging us in and out all right so create constructor first and in here we'll ask for http client add the using statement we'll call it client and then we'll ask for the authentication state provider add another using statement up there it will pass in the off we'll call it auth state provider and one more is the i local storage service we'll call it local storage and we're gonna yes this is growing off the page so we're going to do is there's a new refactoring in the quick access refactoring right right click or control dot and you can say wrap every parameter and then say which type of wrapping you want to do that one's fine so we have our our three items here the http client the authentication state provider and the i local storage service we're going to do a control dot and create a field for each of them there we go so now we have a field for each of those up here that we can then use in other methods inside of our class which we're going to do next we're going to create two methods here the first one is going to be public async task of type authenticated user model and that's going to add a using statement we're going to say login pass in authentication user model and user for authentication that sounds good okay so uh this is where the naming maybe you want to change it it doesn't make sense to you it seems to make sense to me um the authentication user model is that email address and password the authenticated user model is the result okay so this is the request this is the result okay so we have our login whereas say var data equals new form url encoded content new array there we go new array and let's put our curly braces inside here new key value pair string string the oops grant type is going to be password now does this look familiar to you let's put a comma here well i'll put our semicolon at the end i'm going to go look for this this should look familiar to you we're going to have two more of these in here but if we go to our our solution explorer and go back to our wpf library or class library for wpf project and we go to i believe it's the api helper and we come in here there we go see that we're doing exact same call here except that um we're doing it in the blazer web assembly project instead of the wpf project so in fact i'm going to copy these two lines including the comma i come back over here paste it in now using a password don't have that well we do user for authentication dot email and user for authentication password okay so that's the authentication user model that's the request notice we're going to say hey i want to do a grant type of password there's my email and pass email and password where i'll form and code that and then we're going to call our api so var auth result equals await client dot post async we need a url here let's just do https localhost uh port 5001 slash token this is going to be our um our api for now again this is roughing it in we're going to put this into our um into somewhere else um we have a blazer web assembly so we don't have an app settings.json we can figure out somewhere to put this that's a a string constant of some kind and actually could probably put this into some type of uh of changeable thing outside the built process so that we can change it during our deployment process as well so this is not the end spot for this okay this is not where i would leave this because then it will only work if your api is at the local host port 5001 which makes no sense because in the real world when you publish production you're not going to have your api at localhost so this is going to change that's okay we're gonna pass in the data as our payload right so that's gonna give us the result so var off content equals await auth result dot content dot read as string async so grab the result and put into auth content if auth result dot is success status equals false now i could have said put the bang in front of this and taking this out okay that would have worked but notice how easily this blends in with this i'm not a big fan of that therefore i'm going to say equals false and be explicit about it again remember that code is meant to be read by humans not computers humans therefore the easier you make it to read the better it's going to be so if it's false then return null meaning if you have not had a successful call then just say null for your authenticated user model that means you haven't logged in and we go and check that remember back in the um let's go back to our off state provider we do the check if it's null or white space the token they return anonymous that even if we you know capture the token save that if it's null which we're not going to save it but if we did it would still come back as null therefore it would still be marked as anonymous so either way if if this fails for whatever reason you're not going to be authenticated which makes sense the only way you can be authenticated is if this returns a valid token that says you are in any other case you're not authenticated so if it's not null i'm sorry if it's not unsuccessful so if it is successful then we're going to do is say var result equals json serializer which does add a using statement again notice there's a lot more using statements here um i'll try and scroll up to the top and make sure you get all the using statements just in case you don't if you ever have a red squiggly on something that isn't on mine do a control dot and just see if it says add using if it does do that and then you're good to go okay json serializer dot deserialize to authenticated user model the auth content with um let's do let's leave it alone we could do so there's an option here i want to point out let me put in the code just you can see it um the option is to say new json serializer options and then inside these options let's put a closed clear brace we have it um let's let's do this let's put this down here and this down here so that this is more readable the options can be property name case insensitive equals true okay and there are other things you can do in here notice the other options but by saying property name case insensitive if you didn't control the api and you wanted to make sure that it matched even if you your case sensitivity is different for example json typically is camelcase meaning the first word is all lowercase whereas c sharp tends to be pascal case which is every word gets the first letter capitalized by saying property name case insensitive what you can do is take in valid json which is camelcase and essentially convert it to pascal case with just this ignoring uh case uh sensitive okay so basically saying i don't care if it's case sensitive in c sharp make the comparison case insensitive so it puts it in the right places so in our case it doesn't matter because we control the api and the api is valid i believe but either way that's going to ensure that our results are correct now we capture the result that's we've deserialized the value into the authenticated user model and put that into result right well now we're going to say await local storage dot set item async and the key is gonna be auth token and the result and they then they um where i say result dot access token okay so if we get if this is a valid success code then we're going to deserialize into this authenticated user model this right here which has two things in it the username and the authent or the access token we're gonna store the access token in local storage under the key auth token remember auth token that we used over here right there where we looked for auth token to find out if there's a token already stored in local storage well this is where we store it so we're we are storing it in local storage and notice how easy it is to store stuff in local storage it's just set item async you give it the key and the value so really easy to use um you only have a limited amount of space i think it's five megabytes unless they've changed it more recently but um you can't store infinite stuff okay it is volatile it's gonna go away but this can be a great place to cash information especially for offline use all right now that we have that done now we're gonna do is we're going to notify the user or notify the system i guess you'd say so we're going to say two parens to open auth state provider off state provider dot notify user authentication result dot access token so i trigger that notify the user which if we go over to the this right here the notify user passes the token it's going to trigger that state change for authentication after it has parsed the claims and created that off state okay so it's going to parse all the token information into claims and that's going to notify the system that the state has changed with all the claims associated with our logged in user okay plus one more thing to do and that is on our http client we're going to say default request headers authorization equals new um authentication header value which wants me to put the whole name let's do a control dot here to add the using system.net.http.headers make that a little shorter and say bearer and result dot access token so whenever we get call now using our http client which will cover all http clients it's going to add the header for authorization that says bearer and the token so that now our our calls are authenticated and then return result there we go that is the login method now if you have a login method you should probably have a log out method so public async task log out now the cool thing is log out it's a lot easier to do oh wait storage dot remove item async off token don't forget to do this step if you don't remove the token even if you were to do other things like say hey they've logged out that token still the next time they check for the token it's going to say oh there's a token and basically log them back in so you have to get rid of that item in local storage don't just clear local storage because we're not i mean we are right now just using local storage for our token which is not very much but if we were to use our local stores for other things as well when they logged out clearing local storage would delete everything and maybe that's okay maybe you're saying you know what yeah but if they stored something locally that pertained to something like i don't know um their security clearance so maybe they have you know offline report information and that's sensitive information semi-sensitive so we put that in local storage for caching purposes but they log off we want to get rid of that as well that's something to think about but that's not something i would do here what i would do is i would listen for the log off notification i would subscribe to that event and then i would do a clear somewhere else that does that so just know i wouldn't put the clear here even if you're thinking well i want to clear everything because there's some things that may not want to be cleared because they're not pertaining to a particular user or security login for instance maybe you keep track of the last three people that logged in at the station for quicker access to fill in their username okay so you can click on their username and just type their password in well that would not be something you want to clear out if one person logged off because that would clear for everybody they mess so just want to point that out real quick all right off state provider we're doing this cast here so that it knows what type it is auth state provider okay the auth state provider is it's an authentication state provider so we ask for it as an authentication state provider which means in our dependency injection system we're going to ask for hey give me your authentication state provider but that's going to be our custom off state provider okay so this is from microsoft this authorization dot authentication state provider but what we've done is we have kind of extended that with a child class that has some more stuff for example it has the notify auth authentic or notify user authentication and notify user log out so because it has that extra stuff we can't call that extra stuff unless we first cast it to the right type okay that has the additional stuff we need like the notify user logout so if we had just said let me just show you here we have that it's going to say i don't know what that because the authentication state provider does not have a method called notify user logout but if we cast it to type off state provider which that's what this is right here is a cast but then you wrap the whole thing in parens so that we can then say dot and be able to access those additional methods so notify of log out and then also one more thing client dot default request headers dot authorization equals null wipe out the request headers as well so that if they're calling the api they don't have access to sensitive data because we're wiping out those those authorizations okay so those three lines are all we need to log out log in little more stuff to do but log out is a pretty simple process now we are almost done so let's close out of these two go back to our solution explorer i'll pin this for now and let's collapse down our wpf so it's not in the way let's go to program.cs and in here actually let's unplan again in here we have our setup for our dependency injection system okay so we need to add a couple of things here and let's do them uh right here but i'll leave a space in between on both sides we're going to say builder dot services dot add scoped and we'll sign say i authentication authentication i spill it right service we'll do a control dot here to nope that's not right oh you know why it's not right i know why it's not right watch this authentication service which that's going to add a using to portal.authentication and we're good i never create an interface for this so authentication service this is what we just created with the login and log out i want to create an interface with this so control dot and say extract interface which just to verify what's going to do create an i authentication service it's going to put it in a new file okay there we go it's now implemented and it now also recognizes it this allows us to replace this later and not affect any of our application as far as having it change code anywhere else we can just use a different authentication service later if you want to or even in our unit testing builder dot services dot add blazered local storage which is going to add a using statement okay so we got a using statement here for blazer.local storage builder dot services dot add authorization core that's going to add the the net core authorization that's part of the nuget package that we brought in with the um system.net or system.asp.net core components.webassembly.um i thought i wasn't sure it was hosting maybe it adds to the hosting as well um but anyways that's part of the the nuget package we added for authentication okay next up is builder.service dot add scoped for authentication state authentication state provider all right now it's the class but the type we're going to give it is off state provider like so now remember before um authentic the auth state provider that implemented the cl i'm sorry inherited from the class so inherited from authentication state provider well that's what we're gonna expect everywhere is an authentication state provider but we have our custom one that does additional stuff and so we're passing that one in now right now my code has to cast to this type in order to um to get additional stuff i'm not we've got to think about that long term because if we ever replace this with something else we have to change those casts as well so unless we then inherited from this class and did additional things so that might be possible as well but um just know whenever we ask for authentication state provider we're gonna pass in hours so that takes care of wiring up the dependency injection system so if we ask for local storage or anything to do with authentication or off state provider or authentication services it will give us the right information okay so one last thing to do in this lesson is we have to go to app.razer now in here we've got this router that's set up for not using authentication there's there's no um there's no setup here for using authentication so we're gonna do is change that so if we found the route right now it just says okay go to it well we're going to change that to authorize route view which is going to yell at me because it says hey i don't find that markup element that's because we need to add some information to our imports.razer so the first one we'll add right here using microsoft dot asp.net core dot components dot authorization and the next one is going to be actually right above it so using microsoft dot asp.cor dot authorization okay we need to add these two using statements to our file and i think what we'll do is we'll leave it like that for now we'll probably need to add more when we create the login page um but we'll leave like that for now but notice now that it says authorized route view is fine because it knows about the microsoft asp.net core.components.authorization.authorize routeview but we need to do more in here than just go to the route let's take this slash off which means we need a closing statement but inside here i want to have an authorizing tag and you could have anything you want in here but i'm just going to create really simple and say text we'll say please wait wait there we go we are authorized you okay so if you are if you find the route and we're in the process of authorizing them meaning we're going out and figuring out if they're authorized or not pulling in that that jwt and parsing it from the local storage then we'll see this text temporarily it says hey just wait we're authorizing you right now okay and then it will just show them the route but if they're in that state where we're we're kind of waiting on something we don't want to be a blank screen that looks like it's locked up we're just going to tell them hang on it's coming um we'll get there you know as soon as it's done which should be very very short but just in case that happens we want to make sure that um that's shown now for not found we need to cut this out so we can wrap it in a cascading authentication state and we'll paste it right back in so this is going to say hey it's not found wrap it in this cascading authentication state so we can know um what the information is about the user because this is about the route but we also need to know about the the user if they're logged in or not and the information about them and that's the last of our changes for this lesson that was a lot okay that was absolutely a lot of changes we have our four new items in the authentication section we have our two models which hopefully will get moved into a shared models at some point um and we have our modifications to our imports our razer our app.razer and our program.cs just a lot of stuff going on in this lesson we could continue this point and create a login page in our log out page and then from there create a we haven't touched the idea of registering a user we'll have to do that as well but i think what i'll do is i'm going to stop the video here we're going to um come back to this in the next lesson where we create that login page and the logout page test this against our actual api make sure it's working and then start doing some of the extraction to make it better take those um those uh constants out and also have a place to put our urls we can change it when we go through the publish process so that we don't have to recompile our application every time we change our api's url so we'll do at least the login logout and testing in the next video i don't really be hanging forever though um so instead of doing every other week and being two weeks out to the next video what i'm gonna do is i'm going to make the next video um the continuation of this kind of a part two to this where we do the login and log out for our authentication system and do the testing of this code because we haven't tested this yet to make sure it works it does work um i'm very confident of that but we need to test it because it's a lot of code to type out it's a lot of code to get right it's a lot of complex stuff so we'll do that in the next video which will be just a week from now okay thanks for watching if you have any comments thoughts uh concerns things you want to bring up leave them down below i can't debug your problems necessarily i can't um give detailed views and i don't necessarily have the time to even answer every question anymore sorry about that i i do try to answer um as many as i can um and tom my community manager helps out as well but um but definitely down below because i'll take a peek at those comments and make sure that if you have thoughts i at least write down in my notepad of things to do later or things to think about and if you have any thoughts on ways to make this even better or wrap this up into some type of quickly reusable drop-in system for a blazer web assembly project i'd love to hear them again i can't debug a code or necessarily do a code review of it but i'd love to at least hear you're working on it so thanks for watching and as always i am tim cory
Info
Channel: IAmTimCorey
Views: 29,624
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, course, training, how to, tim corey, C# course, C# training, C# tutorial, C# app start to finish, timco, timco retail manager, wpf, asp.net, .net core, dependency injection, blazor webassembly, blazor webassembly .net 5, blazor webassembly authentication, blazor webassembly authentication and authorization, blazor webassembly jwt authentication, asp.net core
Id: 2c4p6RGtkps
Channel Id: undefined
Length: 74min 17sec (4457 seconds)
Published: Mon Mar 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.