Spring Security 6 | How to Create a Login System with Spring Data JPA and JWTs [NEW 2023]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Spring Security can be seen as a massive rabbit hole if you go on YouTube and search up Spring Security tutorials you're probably going to run into hundreds if not thousands of different tutorials except many of the Spring Security tutorials are either going to be out of date or barely hit the service of what you're actually going to need inside of your Spring Security application this means that you're gonna have to go on and search for even more and more and more tutorials that are either going to be out of date or way too complex and congratulations you've now entered tutorial hell this is exactly where I found myself when I started researching to start building the let's build Twitter series on YouTube I need a backend service with password encryption and I knew that Spring Security is probably the easiest most straightforward way to do this namely with the beatcrypt encryption library then I went from tutorial tutorial running into Old tutorials tutorials that are way too complicated and tutorials that we're using deprecated features the framework that I should not be using anymore and then whenever I finally did find a tutorial that was not out of date it was only shown me very basic user authentication and things that weren't going to be that useful for me inside my own application and eventually after watching hours and hours of Amigos code in Dan Vega I'll explain the ability to take all those different tutorials and I can finally piece all those things together to get to the point where I could actually make my backend application be what I actually need for my service and all that is my goal of today's video I want to create this video to save you guys all the hassle and time it's going to take to go through and watch all the different tutorials that I had to watch to get to the point where I'm at now and put it into one single video for you to watch right now what I'm gonna do throughout this video is I'm gonna go ahead and make a back-end application for you that's going to be meant to be paired with a front-end application that's going to have built-in password encryption it's gonna have access to databases it's going to allow you to make HTTP requests to log into user and register a user and it's also going to go ahead and generate JWT tokens for you to go ahead and authorize the gifts whenever you make requests to user specific routes I want you all know this is only meant to be a crash course to get a very simple API up and running and then from there you can go ahead and add whatever features that you might need for your own application this code is going to be available in a GitHub repository in the description below but I would really recommend going ahead and watching this entire video that way you can get some tips and tricks and context as well about what we're actually coding inside the project we aren't going to be going super deep into the inner workings of Spring Security in this video this is just like I said a crash course on how to get everything set up so if you do want to go ahead and go deeper I would definitely suggest checking out Amigos code or Dan Vega the they're both really good resources on Spring Security I'd highly recommend watching them if you do want the basics but obviously come back to this video that we can get an all-in-one with jwts database access and logging in with HTTP requests as always I'm Ethan or an encoder as my day job I actually train software engineers and I do want to make a small disclaimer all the content that you're going to see in this video is all mine I would never take or use any of the intellectual property from my own job I don't even try and Spring Security Mount job this is all a pasture project and a side project I'm working on on my own so with that being said let's go ahead and hop onto my computer behind me and I'll start taking a look at what we're going to need and how we're going to start this project out of course this Project's going to have a few prerequisite pieces of technology and other things like that you're going to know beforehand first off of course we're going to need a code editor or something like an IDE this project actually trialed out VSCO in the next slide I'll go ahead and give you the extensions that I used of course you could always use Eclipse Enterprise Edition spring tool Suite or IntelliJ I would suggest either Eclipse Enterprise Edition or IntelliJ the only downside of IntelliJ is that you have to pay for the premium and pay for ultimate to get the spring initializer however with vs code and with Eclipse Enterprise Edition you can go ahead and download the spring initializer for free if you do go ahead and want to follow along with me and use the vs code all we need are the extension packs for Java and the spring boot extension pack this is going to get you everything you need for developing Java applications as well as anything you need to develop spring boot applications make sure you get the Java developer pack from Microsoft and that you get the spring boot extension pack from VMware that way you know that you have the right packs next of course we need our languages so we are going to be using Java 17 for spring boot version 3.0 plus and then you'll also want whatever your flavor of SQL is for example I typically use postgresql but there's plenty of other languages as well finally you're going to want some underlying understanding of spring Boot and probably spring data for this project this is not an introductory level tutorial so I'm going to go ahead and assume that you've used springboard before and you might have even used a little bit of spring data as well so with that being said let's go ahead and hop in and I'll show you guys what we're building for this project this is the application we're going to be building throughout this tutorial let's go ahead and start at the very front all of our requests are going to come through this thing called a security filter chain and this is where we're going to decide whether or not and how we are going to go ahead and authorize or authenticate things some of the requests are going to be sent straight from the security filter chain into our authentication controller and these are going to be requests like login and register so we don't need to be authenticated to go ahead and do those and then the request that we do to be as indicated are going to go through this oauth resource server because these are going to be because these are going to have jwts attached to them these are going to be things that are locked behind rules such as user and admin for the time being we don't really do we don't really expand upon the user control and the admin controller because we're just trying to show you all how to set up your authentication everything so going back up to our authentication side whenever we make a request without indication controller we're going to talk to one of many services if one of the requests might be to log in so to log in we'll need to go ahead and talk to the user service which we'll need to talk to the authentication manager and then pass back an authentication token to our token service to send back to the user or if we are going to go ahead and register we're going to send a request to the authentication Service which talks to the user and so on and so forth we're gonna have two databases one for user and one for roles which will be communicated between the user service and the authentication Service and then the token service is only going to be used to create and generate JWT tokens so that means said let's go ahead and generate our project and hop into our development so we're going to start out at start.spring.io where we can find the spring initializer this spring initializer is a tool provided by the spring team to easily generate spring boot starter projects for us as we can see and the reason I'm opting you spring initializer here is because I want to keep the project set up as universal as possible you can easily set up a project here and import it into any ID that you want including vs code IntelliJ Community or Ultimate Edition Eclipse brings tool Suite or any other code editor that you may use if you are familiar on how to create a spring starter project inside of your code editor by all means go ahead and do that I'm just trying to keep this as simple as possible so now getting into the project setup the first thing we want to do is choose our project type you can choose whichever build tool that you're familiar with I prefer using Maven so that's what I'm going to go ahead and choose again if you prefer using Gradle with either groovy or kotlin feel free to select one of these let's go ahead and select Maven next we are going to be using Java as our language again if you guys using something else feel free this is a Java based tutorial though and next is probably the most important one and this is for the spring boot version so the spring boot version is going to be a very important decision if you decide to use version 3.0 plus you will have to use shallow version 17 plus I train software Engineers on Enterprise level development and majority of enterprise software is still using Java 8 with the very smallest percentage of those Enterprises switching over to Java 11. so personally I like using versions 2.0 plus of spring boot that way you can use Java 11. the largest difference you'll run into between spring boot 3 plus and spring Boot 2 plus is that whenever you're working with data persistence in Java 17 you're forced to use the new Jakarta packages instead of the old Java X packages with that being said we will go ahead and choose version 3.0.4 for this tutorial that way it's as up-to-date as possible next we want to fill out the project metadata information starting out the group ID you can set this to whatever you like typically this is going to be reverse domain of whatever company you're working at I don't have a domain land or a company so I'm just going to put it as unknown coder next we need the artifact ID so this is going to be basically what your project is called if you are building a service that would be going on to the maven repository you'd want to make sure that you're using lowercase for this I'm just building a standalone service that's not going to go on the main repository or anything so I'm just going to use uppercases here and I'm just going to call my project name authenticated backend again if you're going to be putting this on the maven repository you'd probably want to go ahead and name this lowercase with dashes in between for the description you can put whatever you like for us I'm just gonna be putting in Spring boot Spring Security authenticated back in because that's exactly what we're building and finally for the pack of Shame if you want to keep it as authenticated back and you can although I'm just going to shorten mine to com.unnencoder again this is going to be something important whenever we get into building things that like services that are going to go on to the main repository but again this is going to be a standalone project that we're just running I'm not worried about it finally we are going to keep the packaging as Char and as we talked about earlier if we're using version 3.0 plus we are going to have to keep Java version 17 plus if you do want to be at the latest and greatest you can do 19. however 17 is the most recent long-term support so we are going to go ahead and keep that now that we have our metadata all filled out we can start talking about our dependencies we're going to start out by building a very basic backend service and then we're going to start securing it with Spring Security and jwts so we'll start out by adding spring web this is going to allow us to create our service routes which will eventually be called by your front-end client next we want to add spring data jpa this will allow us to easily access just about any relational database that we want this is where you'll see the biggest change between Java 11 and Java 17 instead of using the interface from java expert systems package you'll be now using the interfaces from the Jakarta persistence API which should act very similarly if not the same now we will add the driver for HQ database I want a database to query for user credentials to show you all how to actually do that however I want to keep this focused on Spring Security and not setting up a database you can basically sub out any relational database you would like in this situation I will be setting up the H2 file database to act just like a postgres database just so you all know if you are interested in using some other relational database or relational database not supported by jpa for some reason you can always look into some of those other spring data Frameworks as well finally We'll add spring boot Dev tools which will disable caching during development and also live reload a server anytime we save our backend code now that we've got everything filled out we can go ahead and hit this generate button at the bottom of the screen this will go ahead and download a zip folder with the generate spring boot project foreign folder is downloaded I'm going to go ahead and move this over to my desktop just for ease of use and I'll meet you guys over there at the next steps as you can see we have the zip folder on our desktop now all we need to do is go ahead and simply right click it and do open this should open up a Windows similar to this where you can see another folder inside which is the actual project itself again you guys can store this wherever you want but all I'm going to do is go ahead and drag and drop onto my desktop you guys can drag and drop into any folder that you like wherever you put your projects that's all good and now we can go ahead and close out of this folder and delete the zip and finally what we need to do next is open up this project in vs code as we talked about I'm just using the vs code because it's very accessible so all I gotta do is go ahead and right click on this and then open with code whenever it gets opened it should be loading some stuff up and you should see Java projects on the top where you can see the authenticated backend the only issue with the Java projects tab is that you can't see the Palm which will probably need access to later on so keep that in mind however you can use this to great packages and classes and also on the left side you should see a spring boot Dashboard you might see a couple other tabs such as beans and endpoint mappings we're not going to deal with the beans or the endpoint mappings but we will be using this to start and stop our server anytime we want to continue working so with that being said let's go ahead and hop into some coding as mentioned before we're going to start out by building out an application that is just a normal old rest API or an API in general it might not be conforming exactly to rest then we're going to go back through or go into secure that since we added spring data we actually had to go ahead and set up the database connection information first otherwise if we do try to run the spring application it's not going to run it's not going to work to do that we want to go over to Source main resources and then go into our application.properties the first thing that we're going to go ahead and set is to use server Port I like to change this off of port 8080 just because everything runs on 8080 there's likely going to be a clash or there could be a clash so I like to set this to just something like Port 8000 so that's what I'm going to go ahead and do so that's just going to make us that our application runs on a different port now we need to go ahead and set up our database information the first thing that we need to set is the spring.datasource.url and we are going to use the URL to a file on our system so let's go ahead and set that up so this is going to be the URL out to our database like I mentioned before we are going to store this inside of a file and then you can also see mode equal to postgresql this is just basically going to give us postgres type syntax whenever we're working with the database next we need to set up the spring data source driver class and that is going to literally give us the driver for our database connection so this is going to be org.h2.driver because this is obviously the driver or the database that we're using next we can set up a username for our database with spring.datasource.username normally whenever you're using a shoe database we just default to sa then we need to set up the spring.datasource.password this is going to be the default password for our postgres database you don't technically need a password you could leave this off but typically you're gonna have a password you're working with like an RDS or something along those lines so I like to go ahead and add that as well we're going with a super secure password of just password in this instance obviously you could probably either want to use an environment variable for these or just have a properties file that's stored on your prediction server somewhere and not push these files up to GitHub but obviously you do not want to leak your database credentials now we need to set up the spring.jpa.database platform this is going to get our dialect so it knows how to convert the jpa queries over to the platform dependent queries this is what makes jpa so powerful and since we're using H2 we're going to grab that from org.hibernate.hq dialect again you're going to use whatever dialog is going to be needed for the specific database vendor that you're actually using so it might be postgres or mass qo Oracle whatever it is you just swap that out next we need the spring.jpa.show SQL all this does is prints out the SQL in text form inside the console and like a log all this does is actually slows down our application so we do want to get rid of this so we're going to set this one to false and the next one is going to be very important it's going to determine how our database is set up and tore down if it is or not and this is spring.jpa.hibernate.ddl-auto and for the time being we're going to set this to create drop and what create drop does is going to create the database schema then whenever we go to shut down the database it's going to clear out that database schema and this is useful whenever you're first starting development and then once you get done with that you're going to want to change this to update which is only going to update the schema whenever you need it updated rather than deleting everything and losing all of your data over and over again so this is going to finish up our application.properties we can go ahead and save unknown code from the future here I was editing and I found a small typo I forgot to fix here on line 9 this needs to be an equal sign not a colon just so you all know you can fix that up now back to the coding and now we should be able to actually go into our spring boot Dashboard and hit start on our application and we should at least be able to see that hey this is working and it's running as you see it started it might have had a couple of Errors because it can't find some queries and stuff like that as we see let's see what this error is um I'm not seeing it typically it's because it can't find something oh it's probably because it couldn't find our database because we need to make that database file but everything is working out all right and that actually tells us that we do need to go ahead and make that file for this we need to go back into this so we can make a new folder I'm going to right click and make a new folder and I'm going to call this data because that is where we're storing it data and I'm going to make a new file and I'm just going to call this demo and now all of the data is going to go inside here and if we live reload our server if we got a slash in the data and save and now we should be getting rid of that exception or that error there we go so always remember the slash after file and now that's all good to go no more errors inside the console whenever we're starting it up and we can start actually developing the application that we are set out to there's many different ways that we can actually set up our application different layers and things like that some people like to keep it in like domain models so for example everything related to a user or everything related to I don't know a log or everything related to a post I like to break my layers up into like service layer model layer controller layer and then any other layers like repositories and anything else that we might need so for the time being what I'd like to do is just go ahead and set up some of the layers firstly I want to start with the controller layer and just make a quick request mapping to a slash that way we can see that we can make access to it we haven't added any Spring Security or anything like that yet then I'll show you perhaps whenever we actually do add Spring Security the first thing I want to do so I want to go ahead and right click on our com.unnencoder and create a new package and this is going to be our controller package so I'm just going to name that controllers and open this up and then inside of a controller package we're going to have a new class name we're going to call this user controller so this is going to be user related request we're not going to go that deep as when I show you guys locking everything down and all of that good stuff so we do need a few annotations so first we need an at rest controller annotation and of course this is going to come from Spring web we also need another annotation called at request mapping and we are going to map this controller to slash user we need to also import this and finally we're also just going to do this a quick and dirty way we're just going to add cross origin you'd want to prevent cross origin to basically just specifically your IP or your port or your whatever I'm going to just say everything just to make things simple you'd want to be a little bit more secure than this so we need at Cross origin and inside we're going to have a star inside of quotes and let's go ahead and import this as well and now we are ready to start setting up our first user controller inside of our user controller class what we're going to go ahead and do is we're going to make a very simple git mapping which is going to map to a get request so we can make from something called Postman first let's make a public method that returns a string called hello user controller inside of this we're just going to return some text saying user access level because this is going to signify that hey this is accessible by a user and then the last thing we need to do is go we need to go ahead and map this to a specific endpoint inside of Slash user so for that we're going to go above it we're gonna need a new annotation called at git mapping and to keep this somewhat restful we're going to just say slash go ahead and import this so now what we've got here is a quick application it's not talking to a database or anything like that currently what it's going to say is if we go to localhost 8080 slash user slash is going to print out user access level and eventually we're going to lock this down so that only users can access this and we also want to make one more controller really quick inside the controller package called admin controller so let's go ahead and do that so we're going to go ahead and click on new and we're going to make a class called admin controller and inside here we're going to need the same exact annotations we're going to need at rest controller to make this a component of spring we're going to need at request mapping to tell spring hey we want this to be mapped to slash admin and finally we need at Cross origin that way we can make requests across different Origins so this is going to be more useful whenever you get into building your actual front end that way you're not getting blocked by course now inside of admin controller I just want to make one more quick git mapping similarly to how we did to the user controller let's go ahead and make a quick string method that just returns admin level access similar to how we did for the user controller and as I said this is just going to return a string of text saying admin level access similarly to how we had in the user controller we need another at git mapping above this that way we can say hey we want another route inside the admin controller in the route that we're going to use is just slash so again this is going to be somewhat restful so if we access HTTP colon slash localhost colon 8000 slash admin slash we're going to get the admin level access as we get going down the tutorial we're going to start locking these down that way a normal user cannot access admin level stuff we're going to make it so that an admin can access admin level stuff and use the level stuff and then someone who's not logged in at all won't be able to access anything whenever we save our server restarted and everything is good to go now I'd like to do is go ahead and open up an application called Postman and actually attempt to make a request to each one of these routes this is what our Postman looks like what I want to go and do is go up to this plus Mark and I want to make a new request to http localhost 8000 slash user slash so now if we make a get request to localhost 8000 slash user slash we should get text back saying user level access let's go ahead and tempt it as you see we get a 200 status and we get user level access if we do the same thing with admin we should get the same thing admin and send you see admin level access So currently we have a very simple web application that we can send request to the backend and get a response back to our client typically what this is going to end up being is some front-end application stored on a web browser what we actually want to go ahead and do now is try to lock these down I'll show you guys what happens after we lock these down back inside of our Visual Studio code now we actually want to go ahead and add in the Spring Security that way we can actually lock this down and not allow just anyone to access our data so what we're going to need to do is we need to go ahead and right click on our authenticated backend go to Maven and open Palm file we need to add a new starter in here the spring boot starter security that way we can actually add in Spring Security and by default spring security locks everything down so you can't access anything whatsoever so anywhere is fine inside the Palm I'm just going to put it right here in this empty space when you start out by just adding dependency inside of angled brackets and whenever we enter it should close them for us I guess not so we'll add a closing tag as well and inside of the dependency is we're going to store the information we need a group ID and an artifact ID and then Maven will handle the rest first we want to start out with group ID and this is going to be auric.springframework.boot and then we also need the artifact ID the artifact ID is going to be spring Dash boot Dash starter Dash security now if we save it might automatically reload so it does say a build with a build file is modified do you want to synchronize sure go ahead and synchronize and this should go ahead and grab the dependencies that we need and this should have automatically locked down our application so to test to see if Spring Security is working we can go back into Postman and we can attempt to make a request to slash admin again and we should get a 401 so Spring Security is not working we had to stop the application and then maybe rebuild and then start the application again and now whenever we come back into Postman and hit send you can see we get a 401 unauthorized if we also go into user and say the same thing we also get 401 unauthorized this is because by default Spring Security is going to lock everything down and that is a good thing now we want to tell Spring Security what we do want to allow and don't want to allow and now we can start getting into let's bring security configuration that you guys are curious about if we actually come back into vs code and if we scroll up a little bit the inside of our terminal and I'm going to make a terminal a little bit bigger as well you should see that using generated security password so what does this actually mean so whenever Spring Security does set things up automatically it's going to do something called a form login so if we actually go into a web browser really quick and if we type in HTTP go on slash localhost Colin 8000 slash user slash it's actually going to open up a login window and by default this is something like admin and then you want this password that was inside of vs code so if you copy this code and go back into your window and sign in maybe it's user I forget what the username is but you can see now again we have user level access so our goal here is to have to make it so we don't have to use that login screen anymore we actually want to just be able to make a get request or a post request for example with the user's credentials and be able to get the token and allow ourselves to actually be able to access the information without going through this hassle we don't need our Palm open anymore so we can go ahead and close that and we do not need our controllers open either what we're going to want to go ahead and do is we're going to want to make a new package for security and we're going to want to set up some Spring Security configurations so what we're going to do is we're going to right click on an encoder we're going to make a new package we're going to call this configuration and inside of our configuration package we're going to make a new class called security configuration the first thing we need to do is we need to tell spring that this is a configuration class and to look for beams inside of it to set up for us so we need an annotation called at configuration inside the class we need to set up something called a security chain if you go back and watch some of the older Spring Security applications you'll see that they do some extending and some weird stuff but in Spring Security 5.7 we're using 6.0 Plus the web security configure adapter that you'll see in a lot of the older Spring Security tutorials was actually deprecated which means that the original way of setting up the security configuration by overriding the configure method is no longer appropriate it's deprecated instead we now have spring create an instance of a security filter chain for us from an annotated app configuration class which we're doing right now we'll also see some other differences as we advance throughout the video as well that means you'll need to make a method that returns a security filter chain and takes in a HTTP security as well as throwing exception let's go ahead and import the things we need to import and what we need to do is we need to actually set up this HTTP and actually build it into the security chain so we want to start out by doing is saying return http and we're going to set up a few things similar to like a builder the first thing that we're going to set is csrf which is cross site request forgery and we want to disable this next we need to set up the authorization of the HTTP request so if we want to get back to the point where before without having to sign in we need to set these to permit all and we'll start locking them down as we go finally we want to go ahead and build this into the security chain which will set up our security for us the last thing that we need to do is we need to tell spring that this should be a bean and to do that we need to add the app Bean annotation on the top of our method now if we go ahead and save it should reload our application and now if we go back into Postman and go ahead and make a request to slash user slash you can see we have user access level back and if we say admin we have admin level access back again and now we want to go ahead and start actually locking this down the way that we want to lock it down rather than the way that string security is trying to lock it down by default at this point we're now ready to start setting up some of our users and some of our roles and things like that so the first thing that we're going to want to do is set up our models so I'm going to go ahead and right click on an encoder make a new package and I'm going to make our models package and inside the models package I'm going to go ahead and make a new class called roll now this roll is going to be special because it's going to implement a interface from the Spring Security framework called granted Authority and this is basically going to be how Spring Security can actually know what the user is allowed to do with different data so what I need to do is go ahead and write implements granted Authority here and go ahead and import that now it's going to complain because it needs to implement some method so we can go ahead and click on the light bulb and add unimplemented methods now we want this to be something that we actually persist in the database that we can have some database table of rules so I'm going to go ahead and annotate this to actually be stored inside of a database so we need to go up over top of the class and we need to add a couple annotations the first one being at entity our entity is going to tell spring data jpa that this is a model that we want to persist in the database and then we also want the at table annotation at table is a optional annotation but it allows us to name the table however we want that way it's easier to find and it kind of follows our naming conventions I like to name my database tables with plural so I'm going to name this rules now we also need to go ahead and import the at table annotation and we're good to go on that front now inside of our class we need the actual properties that we want to store inside the table so the first thing we're going to need is we're getting an ID all of our tables need a primary key so I'm just going to call this private integer role ID and to actually save this as a primary key inside the database we need a couple more annotations so the first annotation we need is at ID from Jakarta then we need at generated value technically you don't but it's going to make your lives a little bit easier and inside of here we want a strategy and we're going to set the equal to generation type dot Auto we need to go ahead and import our generated value and now finally we can also add an at column annotation that column is actually optional but it's used to add restrictions and other things to the column I want to name the column with snake case so basically I want to name it roll underscore ID and this is how we're going to do this and inside we're going to say name equal to roll underscore ID we need to go ahead and import our column and we're good to go there next we actually need the rule in our case I'm going to be calling this Authority because this is going to match up a little bit better with spring security so I'm just going to make a private string Authority then we just enter basic Constructors as well as scooters and Setters so let's go ahead and set those up really quickly you get Authority get her method was already generated for us because we went ahead and implemented this granted Authority interface so what we need to do is instead of throwing unsupported operation exception what we actually need to do is go ahead and return the authority that we put on this role and of course we need a public Setter method to just go ahead and set this Authority then also we need our Getters and our Setters for our roll ID so let's go ahead and get those done real quick all right and that should be good to go on our rule class now that our rules table is set up and our rules model is set up we can go ahead and make our application user model which we used to actually store the user into the database so we'll go ahead and go to our models once again and hit the new file and go ahead and make a application user once again we are going to make our lives a little bit easier on the Spring Security front and Implement a interface that Spring Security provides to us called user details so let's go ahead and do that and go ahead and import user details and then go ahead and implement the unimplemented methods these are all very easy I'll fix them up and show you what to do with them in a second again we're going to use the user details to actually know what the information is about the user and then be able to actually say hey this user is allowed this user is not allowed type of thing so we're going to do the same exact thing that we did in rules we're going to go to the top and we're going to add at entity we're going to add a table and the name of this table is going to be users an import table and now this is going to store the information in a user's table now we're going to need the primary key we're just going to add a private integer user ID and just like last time we need at ID above this so at ID we also need at generated value and our generated value needs a strategy I'm just going to use Auto once again and go ahead and import our generated value and we'll add an at column just so that we can name this user underscore ID in import column now we have a couple other properties the next one is private string username then we want the property private string password and then we need a set of authorities where basically a set of the roles for this user for this we're going to use a private set of roll and then call that authorities we need to go ahead and import set and we also have to do one more thing with this one since we are having a set of roles we need to either do some sort of mini to something mapping for our database so technically speaking many roles can be attached to many users or the other way around many users may have mini roles so we're going to use the app mini to mini annotation and inside here we're going to tell it that the fetch type is going to be eager what this is going to say is that we want to fetch the data for the authorities as soon as we fetch the user information now we need to tell spring jpa where to store this made to many information and we're going to put it inside of a junction table so to do that we're going to need the at join table annotation and inside of azure and table we're going to need a few properties first one being name and a convention that people use for junction tables is to say the first table second table Junction so I'm going to call this user underscore role underscore Junction next we need the join columns or the columns from this specific table that we're in right now and to do this we're going to have to say equal to inside here we're going to say at join column from Jakarta for some reason earlier was not trying to import it and we're going to say name is going to be equal to user underscore ID then we need inverse join columns and this is going to be the column to join or the name of the column from the other table once again we're going to add join column and this one is going to be name equal to roll underscore ID go ahead and import join table and save and we should be good for now it might still air out but it's going to be okay we'll fix it up and let's set up a couple of our Constructors first we'll do a no argument Constructor that way we can set the authorities to at least something empty instead of null go ahead and import hash set then we'll go ahead and do an all argument Constructor now I need to set up a few of the Getters and setters as we can see our good authorities is already set up except we need to return the authorities instead of returning this throw new exception let's go ahead and set up a Setter for that set up a get password for us although we need to change it to go ahead and return the password let's go ahead and set up a Setter for that they've also set up a git username so here once again we want to get rid of this and just return this dot username we need to go ahead and set up a set username and then now we have a couple of Spring Security things that is set up for us so this one is is account non-locked so basically if you set this to false that means that the accounts can be locked down if you set it to true the account is usable so for us we're just going to set up so that the account's usable so let's go ahead and return true here the next one is account non-locked once again if you set this to false that's going to mean hey it's not working anymore you can't access the account we want to go ahead and set this one to return true next one is credentials non-expired once again if you want to lock your users out or something along those lines you can go ahead and have some actual Logic for this we're just going to set true once again and finally is account enabled this is something else you can say hey once you register you have to verify your account once you verify your account or unlock it I'm doing that my lesbo Twitter series but for us I'm just going to go ahead and set this to True once again now our entire models are set up and ready to go we're ready to start actually being able to take in requests storing users on the database checking their credentials and actually making jwts and all that good stuff that we're trying to work towards after having our applications complete what we can do is actually create a new package for our services and we can start setting up the actual logic to go ahead and authenticate a user and get moving on that so let's go ahead and close out of our models that we just created and let's go ahead and right click and make a new package and call this services and inside of services we are going to make a new class called user service now the user service is going to be the actual class or the actual service that goes ahead and determines whether or not the user's username and password match up we're going to want to go ahead and do is we're going to want to go ahead and Implement user Detail Service and what user details service will do is it's going to enable ourselves to specify how we want Spring Security to look for our user during authentication for the time being what we're going to do is we're going to hard code a user in here so I can show you guys how it's working and we're going to modify the configuration file to make sure everything is working as expected before actually connecting it to a database of course once we ever use a detail service we want to go ahead and import this and now it's going to complain because it doesn't have the methods that it's wanting so let's go ahead and import the methods in this load user by username is actually going to go through and look for the users that we want and actually say hey yes this is working properly or no it's not working properly the first thing that we're going to need inside of our user service class is a password encoder I'm going to go ahead and just Auto wire this now and then in the future in the next step we are going to go and show you guys how we get this password encoder so we need to go ahead and import a private password encoder and import this password encoder then we want to use the auto wire annotation above this to go ahead and auto y a bean of password encoder and go ahead and Import Auto wired this is going to fail for the time being because it's not going to be able to find a bean of type encoder that is completely fine we'll fix this in a little bit inside of our load by username I just want to make a quick tracing print statement here that way we can actually see that our application is inside this user service and inside of the print statement let's just print out that we're in the user Detail Service so now from here let's go ahead and just see if the user's username is Ethan if the user's username is not Ethan then we're going to throw a new exception otherwise we're going to go and return a new user called Ethan cool now we need to go ahead set up Ethan's roles so let's go ahead and make a new set of roles let's go ahead and make sure our set is imported now let's make sure our role is imported from models and we'll also go ahead and make sure a hash set is imported as well let's go ahead and add a single rule called user and then finally we need a return statement and go ahead and return a new application user with our username and the password encoded let's go ahead and import our application user from here and what this is going to go ahead and do is it's going to check to see if our username matches what we expect if it does we're going to return a new application user with a random ID this is obviously just temporary the person's username as well as the password this encoder dot encode we'll see a little bit more of this later but this is basically going to Hash our password for us we also are going to use the same encoder to unhash it or whatever or check the hash whatever you want to call and then finally it has rules of user and then if the username is not equal to Ethan it's not the person we're looking for it's going to throw a new username not found exception and what's going to happen with Spring Security in a second is it's going to say hey we found an application user that means that this person is good to go that's the username password otherwise if it doesn't it's going to say hey this user is not who we're looking for now before this user details service is actually of use to us we actually have to go back into the configuration file and set up a couple of things there back inside of our security configuration file what we're going to need to do is one when you set up a password encoder and that's the thing that we're using inside of our Detail Service we also need to set up the authentication manager which is going to basically say hey how are you authenticating these users let's first go ahead and set up our password encoder what we need once again is the app being annotation then we need a public method which returns a password encoder from inside this method what we want to do is go ahead and return a new bcrypt password encoder go ahead and import our bcrypt and import our password encoder now anywhere that we need a password encoder it's going to return the singular Bean of the bcrypt password encoder that we created here now we need an authentication manager like I mentioned before this is how spring Securities actually go through and figure out whether or not this user is actually supposed to be authenticated or not so once again we're going to need The annotation at Bean and below the Appian annotation we need a public method that returns an authentication manager and takes in a user Detail Service so now this method is going to have to set up a couple things the first thing we're going to want is a dial authentication provider because we are eventually going to be using a dow we just want to set this to a new dial authentication provider now I'm going to go ahead and set this Dao authentication provider's user service that way it knows where and how to look for the user to authenticate finally we need to go ahead and create a new provider manager passing in this Dao authentication provider inside's Constructor and return that out of this method now we are missing a few Imports let's go ahead and import everything that we need so we need the authentication manager let's go ahead and import the user details service from Spring Security we need the Dow authentication Provider from string security and finally we need the provider manager from Spring Security and save and it appears we forgot to add the app service above our user service let's go ahead and fix that so above our service classes we do need the at service annotation that way it's going to tell spring hey make a bean of this type and save and now it should be able to configure for us for some reason sometimes vs code is a little bit finicky all I have to do is save again and not fix whatever error was there now to show that our user service is being used properly as a user Detail Service we're going to have to go ahead and modify our security configuration a little bit the first thing that we're going to want to do is go ahead and get rid of the permit all and actually say authenticated instead now instead of what it's going to do anytime we try to make a request it's going to force us to authenticate in some way and in this way instead of being stateless for the time being we're going to set this to HTT basic which is basically saying hey pass in your username and your password through an HTTP form and then we'll go ahead and authenticate it that way I'm not sure why it's throwing a hissy fit but it's going to be fine so now if we went ahead and opened up Postman again or our HTTP colon localhost 8000 user if we wanted to make this request currently it's going to show us a 401. as you see 401 unauthorized is showing 401 unauthorized because we did not pass in a username and password so what we're going to do now is go up into authorization and then we're going to go ahead and say basic auth and then we want to put in the username so I had a username from before let's just say Ethan and then we're gonna go ahead and put in the password as pass and this should also go ahead and say 401 because the password's not right yeah as you see password is unauthorized it didn't pass in the correct password and if we go back into our vs code you're going to see that we have our Trace message here saying that we were in the user details service so what happened is whenever we made the request into our user controller our security configuration said hey this needs to be authenticated because any request needs to be authenticated it says hey okay our auth manager's user Detail Service so then it went into our user Detail Service and it checked to see okay we did get a user back but the password is supposed to be password the password that we got was pass back inside Spring Security if I actually passed in password properly and sent the request you should see now we got user access level because we actually had the correct username and we had the correct password if we go ahead and put an incorrect username it's also going to send back a 401 as you can see here we're unauthorized because the username is not correct so now at this point we have gotten our application locked down to the point where we had to pass in a username and password with every single request now we do not want to have to do this but we actually want to be able to do is send in our username and password just once have the application send back a token for us and then put that into a auth token or a bearer token as we see here instead that wage is a little bit easier and then the back end also doesn't have to hold any state either now we're at the point we're ready to go ahead and insert some users and some roles into a database table and actually go ahead and query that table to see if that user exists or not and if their password is proper or not so to do that we're going to need the repository layers let's go ahead and go into our own encoder and make a new package and call this Repository inside of a repository package let's first make a user repository class so we are going to be using spring data jpa so what we actually want to do is we want to turn this class into an interface and since we are using jpa repository what we need to do is we're going to make this user repository interface extend the jpa repository interface now inside of our jpa repository interface type parameters we need to pass in is the model we're trying to store or query out the database as well as the type of the ID for that model we need to go ahead and import our jpa repository and go ahead and import our application user now this is not a tutorial for a spring data jpa however what spring day jpa does is it's just going to go ahead and generate a whole bunch of queries for you basically a bunch of crud operations and pagination and some other things all you need to do is go ahead and specify specific queries that you want inside of your repository basically all we're going to actually want for our user repository outside of our basic cred methods is going to be able to find a user by the username because this is how we're actually going to see if a user exists in the database and then log them in so what we're going to want to do is make a new method that returns an optional application user and we need to name this find user by username because this is how spring day jpa is actually going to set up the query for us let's go ahead and import our optional and now thanks to Spring data jpa our entire user repository is finished for us before moving on to the next repository we do need to make sure we go ahead and Mark this with at repository on the top now spring will create this as a repository for us now that our user repository is finished let's go ahead and go up to a repository again and make a new class and let's go ahead and call this rule Repository once again our raw repository should be an interface and the interface should extend to jpa Repository and inside the typed parameters we need roll and integer let's go ahead and import roll and JP Repository once again we only need one specialized query out of this so let's go ahead and make an optional method once again and this one is going to be fined by Authority that way we can search for roles by their Authority go ahead and import our optional and now our user repository and role repository are finished there's one last thing I want to do before we start working on modifying some code that's to make sure both of our roles are in the database before we try to register new users as well as making sure there is an admin user that way the admin can do some administrative tasks if we ever wanted to this is because it's probably not a good idea to let someone sign up as an admin because if you allow that then you might have random users signing up for your website or for your API that can say hey I'm an admin and get access to things that you don't want them to it's better to have some administrative role that can go ahead and update some other users role to admin and allow them to be admin that way rather than the other way around so what we're going to want to do next is go into our authenticated back-end application and before we get too ahead of ourselves here working on inserting new users and roles into the database let's go ahead and throw on the at repository above the role Repository this is not strictly required but I do like to make sure that we do go ahead and annotate all of our repository classes the authenticated backend application is the main method or the main entry point of our spring boot application it's going to set everything up for us and what we want to do inside here is we want to go ahead and set up something called a command line Runner which is going to run some code as soon as our application starts up the reason that we want to do this is because we want to make sure that whenever we spin up our application after we went ahead and destroyed all of our schema we want to make sure that we at least have an admin user in here and we also have the rules that we need we can actually do that with the row repository and the user repository as well as running with the command line Runner so to do that we're going to go ahead and go into this main class and we want to use the app Bean annotation over a method that returns a command line Runner and the method that Returns the command line Runner we're just going to conveniently call run this method is going to take in a few things namely the things that we want to inject so we're going to need to inject the role repository the user repository and a password encoder now we need to go ahead and make sure that we import all this stuff so we need to go ahead and import our command line Runner we need to import our role repository we need to import our user Repository I'm going to import our password encoder and these are automatically going to be injected for us now it's complaining because we need to go ahead and return some command line Runner to do that we're going to use the Lambda function so we're going to say return and an arrow and then args and then on the inside here we can actually run our logic so the first thing we need to do is we need to go ahead and make our rolls the first row we're going to go ahead and store into our variable because we're going to apply that rule onto a user let's go ahead and import roll anytime our application starts up it's going to add in this row let's go ahead and add the user type row now we have our user rule saved now what we're going to want to do is going to go ahead and set up the rules for our admin user so to do that I'm going to go ahead and make a new set of rules called roles go ahead and import everything we need so we'll need a set and a hash set now let's go ahead and add this admin rule into our roles and finally let's go ahead and make this new application user that will call admin now we need to go ahead and import our application user and now this is actually ready to go ahead and save so now we need the user repository.save now that is all good to go the final thing that I do want to go and do is what if we turn off the create drop and then turn it into update so we're going to need some way to check to see if something exists in there and if the for example if the admin rule already exists that means that the user rule must exist and also the add-on must exist because this command line Runner has run so you want to go ahead to check to see if this exists so we can do that with a simple if statement and inside the if statement we can go ahead and call the role repository dot find by Authority then we want to go ahead and pass an admin however you'll see that there is an issue here there's an issue here because this doesn't actually turn a row it's actually going to return optional so what we can go ahead and do is we can go ahead and say dot is present so if we find it we want to go ahead and just return to exit out of this method and there we go so now our command line Runner is set up anytime our application restarts and we had tore down our database is going to go ahead and re-insert all this information otherwise it's just going to skip over it and then we can go ahead and move on as well now that our application is set up to go ahead and pre-load the admin user as well as those rules we're going to want to go ahead and head into the user service once again and now instead of loading the user from some random name to a hard code we can actually grab that from the user repository back inside our user service the first thing that we're going to want to do is go ahead and get an instance of our user Repository and what we're going to want to go ahead and do is import our user repository and we also want to Auto wire this now that we have access to our user repository I'm going to keep our in user Detail Service just for the time being keep in mind you don't want to keep any system out prints inside your application it slows everything down it's just not great it's better to log but I do want to go ahead and remove all the information we have in here and we're going to set up a new return so now what we want to do is go ahead and return if there is a user in the database with our username otherwise we're going to want to go ahead and throw a new username not found and this is really simple because we used an optional so let's go ahead and first try to find the user by username and we want to pass whatever username that the user passed in the request and now since this isn't optional it's not just going to automatically return the user so it's either going to have a user inside this optional or it's going to be empty if our option was empty we're actually going to want to go ahead and throw a new username not found exception and we can do that very easily using the dot or else throw and then a Lambda calling the username not found exception Constructor and then we can put whatever message we want I'm just going to say user is not valid inside of our exception here you got to love that vs code doesn't persist a word wrap across every file but it is what it is so now what's going to happen is whenever we go through and try to log a user in using HTTP basic instead of doing some hard-coded username like Ethan for example it's actually going to call it user repository which will go to our database find the user in there if it exists otherwise it'll throw an exception so if we head back into Postman one last time and if we try to log in with Ethan and password we should get a 401 because the user with username Ethan does not exist inside of our database as you see we get 401 unauthorized however we do have a user called admin and a password or password so theoretically if we call admin and password we should get the response back saying user access as you see we get user access level because we actually have an admin password in there and if we mess up the password it's not going to work as well we should get a 401 now we are pretty close we can go ahead and actually search on our database for a user and authenticate them but now we want to go ahead and make sure that the user can actually just log in once and verify off that instead of having to pass this username and password every single time we are able to access our routes and everything with the admin user but we're not able to actually create any new users to be able to access our application and that's probably most likely what you're going to want to end up doing so what we're going to do now is make it so that we can allow other people to actually register their accounts and then log into their accounts later on so what we're going to need to do is go ahead and make a new class inside of our services and I'm going to go ahead and click on the plus this will make a new class and we're going to go ahead and call this authentication Service and inside the authentication Service I do want to go ahead and remember to throw the at service annotation on top of this and what app service is going to do is it's going to allow spring to go ahead and create this class as a beam for us the other thing that I want to go and throw on this is at transactional we want to make sure this transactional comes from the spring framework because we want spring to go ahead and manage our transactions between the database and the application and the reason why we're putting this on the service layers because this is where we're actually going to be calling the database layer and this is where we're going to want to make our transactions in what transaction basically does is it's going to make sure that we're going to treat every single one of our methods inside this authentication Service as a single transaction so that way if we're doing multiple database calls and changing multiple pieces today in the database and things of that sort if a method ends up failing or something along those lines it's going to go ahead and cancel out that transaction and the database isn't going to be messed with now we can go ahead and work on the inside of our authentication Service and the first thing we're going to need is we're going to need to go ahead and pull in our dependencies some people may only want services to talk to Services other companies may allow repos any repository to talk to any service typically I just go ahead and allow different services to talk to different repositories so what we're going to want to do is go ahead and pull in the user Repository because we want to go ahead and allow user to go ahead and search for themselves or maybe register themselves and then let's go ahead and import our repository we also are going to want to go ahead and just throw at Auto wired typically you'd probably want to make a Constructor here and do Constructor injection but I'm just going to do this dirty and fast so go ahead and throw Auto wired Above This after we add in our user repository whenever we create a user we're also going to want to go ahead and look for a role to attach to that user or roles I guess multiple rows to attach to that user so let's go ahead and pull in the role Repository once again let's go ahead and import role repository and we'll also need to go ahead and throw at Auto wired above the top of this finally whenever we create a user and whenever we actually go through and search for a user later on we're going to need to go ahead and know how to encode the password otherwise Brink's a curious not going to know what's going on with the password let's go ahead and bring in the password encoder as always go ahead and import this and we'll also want to go ahead and auto wire this as well so now that we've got all of the dependencies that we need for the time being we can go ahead and start working on a register method typically what I'd probably want to do here is instead of returning the entire register user we'd probably want to go ahead and create a user dto to pass the user information over instead of passing in the authenticated password and all of that good stuff or what you can do is inside the user model above the password field you can go ahead and throw at Json ignore either one of these is going to work the time being I'm not going to deal with this I just want to set up a very simple back end so just keep that in mind you don't want to be sending over the password because even if it is encrypted that's still not good practice what we're going to want to do ahead and do next is go ahead and make a new method that returns an application user and takes in their specified username and password foreign we need to go ahead and import our application user that way you can use it right now it's airing out because it's not returning anything so let's go ahead and just return null for the time being to get that to go away now the first thing inside of our registry user method is we want to go ahead and take that password and make sure it's encoded before we put it onto the database and the way that we're going to do this is we're going to use the password encoder to encode method this is going to spit out an encoded password with whatever encryption algorithm that you're using now we need to go ahead and set the rules whenever we register a new user as we mentioned in the previous section we are just going to assign them role user and later on if you want to code something in to allow them to have admin access you go ahead and do that and how we're going to go ahead and get the user role is that we're going to use the Roy repository.find by Authority with the role name of user or in our case the authority unnamed user and then we have to use the doc kit method because this is an optional this is not actually returning the role itself we need to go ahead and import our row that way we can use this and make sure it comes from our models not some and not from somewhere else now we have our password encoded we have our role we need to go ahead and make a set of rules for our authorities we need to go ahead and import our set and hash set foreign need to go ahead and add the user role to our Authority set now that we have our password encoded and we have our user row and authorities all set up you can go ahead and create the new user and store them inside the database to do this we're going to go ahead and use the user repository.save method and then we'll go ahead and just create a new application user with a random ID the username the encoded password as well as the authority so we want to set with it and just like that our application user will be saved into the database anytime this registered user with a username and password is passed in now something that's worth mentioning and something that I completely forgot about or blanked out about whenever we set up our models is that all we're doing is passing in a username and password into the create new user method basically and this could be an issue with our username because what if we accidentally have someone with the same username but they have different passwords so just a kind of bit of a fourth thought you'd probably want to go ahead and throw at column and then unique equal to true on the top of the private string username you'll need to go ahead and import at column now now the usernames cannot be the same and then we shouldn't run into an issue with someone having the same username but obviously different passwords this method is pretty useless at this point because we have no way of actually calling it to call it we're going to need some HTTP endpoint and to create an HTTP endpoint we're going to need a controller so let's go ahead and go up to our controller package and create a new class called authentication controller once again we need to remember to throw on our annotations on the top first we're gonna need at rest controller once again at rest controller is going to allow us to map endpoints to our servlets in the back end we're also going to want to go ahead and add at request mapping an out request mapping is going to allow us to map this controller to a specific endpoint for us we're going to use slash auth last but not least we can go ahead and throw at Cross Origins on this just to be safe that way we're not getting blocked by any chorus issues in this case I'm just going to throw a star in here this is definitely not best practice however I don't really care at this point you guys want to lock this down to only allow maybe specific request types if you really want to get into the nitty-gritty you can even do this inside of security configuration again I'm not here to show you guys this part I just want to show you all how we can load usage from the database go ahead and authenticate them and give them a JWT that way to log in every single time inside of our authentication controller we're going to want to go ahead and have an instance of the authentication Service that way we can actually call our register user go ahead and make sure you import our authentication Service and then we also need to go ahead and throw at Auto wired above this that way spring will automatically inject this for us now we can go ahead and go about mapping our endpoints the first endpoint we're going to need is to be able to register a user so to do that we're going to need a public method that returns an application user and we'll just call this register user and then we'll need to go ahead and import an application user so this stops complaining and inside we'll go ahead and return our authentication service.register user with just blanks for now we need to go ahead and add the app post mapping annotation on the top I'll go ahead and get this endpoint of Slash register once again go ahead and import our post mapping so now this is the route setup currently we're not passing in any information and this is because I don't want to pass in an entire application user every single time we want to register someone especially when all we need is username password and whenever the application has username password ID roles and all of that stuff we're just doing ourselves to service if we make our front end pass in all the information that we don't need so what we're going to go and do instead is we're going to make a new class inside the models and I'm going to call this registration dto so this is going to be a registration data transfer object it's not going to be mapped to the database or anything like that and technically speaking you could put this into a dto package I'm just being a little bit lazy you guys do your code however you like I'm just doing this to be quick and simple and all we're going to have here is a couple of things we're going to have a private string username we're gonna have a private string password and then we're simply just going to have our Constructors and Getters and setters and in our case I am going to go ahead and write up a very quick to string that way we can go ahead and print out this object to make sure everything looks good that is our very very quick and dirty registration dto let's go ahead and hop back into our authentication controller to make use of it now inside our authentication controller what we're going to want to do is inside of this register user we're going to want to take in some information in the parameters what we're going to want is an at request body and then we're going to take in that new registration dto object and let's go ahead and import our new registration dto and what at request body is going to say it'll say hey we are expecting some body or we are expecting some data from this post request and that data is going to be mapped to this registration dto object so now what we can do is instead of having these empty rotations we can go ahead and say body.getusername and we can say body.getpassword so we're literally just using this registration dto to transfer data from the request into our backend that way we can more easily register the user now even though we have this authentication controller endpoint to slash register we still can't quite connect to the back end and if we tried I'll show you what happens so if we want to go ahead and try to register a new user currently if we go up to the top and make a new post request to http colon slash localhost colon 8000 slash auth slash register and then we need to go ahead and put in some data so we're going to go into the body and then we're going to go into raw Json and inside here we need a username field which can just be Ethan for the time being it would need a password field and this can just be password so if we try to register a new user currently and we send the request we're going to get a 401 unauthorized because everything is still locked down we need to go back into the security configuration and actually allow people to hit this endpoint even though they're not authenticated yet so coming back into our application let's go ahead and open up our configuration and inside is security configuration we need to go ahead and modify our security filter chain and inside of our authorized HTTP request we're going to want to add some new information so we're going to go to the end of the Lambda we're going to add some curly braces because we're going to have multiple lines of code and that now needs a semicolon and above our auth.in request authenticated we're going to want to go ahead and add Aus dot request matchers and then we're going to want to go ahead and add the route that we want to match which is going to be slash auth we're going to add slash star star star to go ahead and match any nested routes within auth and what we're going to want to do is instead of this being authenticated we're going to want to allow literally any user to access this so we're going to say DOT permit all so now what this is going to allow us to do is it's going to allow literally any user to access the slash alt endpoint that way they can basically either sign up or log in a little bit and then every other endpoint is going to go ahead and be locked down so now if we go ahead and hop back into Postman and we go ahead and try to resend this request with Ethan and password you should see that now we get a user back with an id2 again you don't really want to return the password you'd probably want to do like a dto to get rid of this you also see the authorities you might not want to see the authorities enable true and all of this good stuff so now we're able to go ahead and create new users and what we should be able to do now is take this user Ethan and then go back into our slash user and we should be able to go ahead and say authorization and put Ethan and password back in here and password make sure I spelled password correctly and now we should once again see the user access level with Ethan uh because we created a brand new account and now we can access that account and at this point we are able to create new users and we can even access the controller so we have locked down against username and password authentication but we don't want to authenticate against the users using a password with every single request instead we want to use a stateless system that checks for a JWT token in the header of every request to determine whether user is authorized to view certain endpoints to do this we'll need to go ahead and use the oauth resource server and its dependencies such as the Nimbus library to generate read and decode jwts for us so first we know what to do for this is go ahead and create RSA key pair to be able to generate our jwts so with that we need to go ahead and hop back into our vs code and we're going to want to go ahead and make a new package called utils so do that we'll go up to our com.unnencoder right click make a new package and we're going to call this utils because we're going to have some utility classes in here and inside of our utils we're going to want new class and we'll call this class key generated utility so you probably guessed it this is going to be used to generate some keys I do got to give a shout out this was originally authored by Joe Granja I hope I'm saying that right which was also included inside Dan Vegas YouTube tutorial series which I got a lot of inspiration from uh but this was set up a little bit differently and I actually adapted it to go ahead and use a single utility class rather than having the code all spread out but I still want to go ahead and Shout Out Joe Granja and Dan Vega because credit Street given where credit is due so this is not going to be a component or anything like that this is just going to be a public class with a static method that goes ahead and generates RSA keys for us that way we can go ahead and set up jwts with that being said let's go ahead and first create a method that is public and static and returns a key pair and we're going to call this generate RSA key so for the time being this is going to go ahead and throw a fit so let's go ahead and return null just to get that to stop so as previously mentioned we actually need an RSA key pair to generate our JWT tokens to encrypt them encode them whatever I'm not a perf I don't know exactly what's going on Beyond as soon as jwts it just needs to be secure we need a way of coding it and decoding it with some algorithm specifically called RSA so what we're going to need to do is we're gonna need to go ahead and create a key pair that we'll set in a second and inside of a try catch block we're going to go ahead and try to generate this for the time being it's probably going to complain because we have no reason for a try catch but it's fine so now we're gonna need is something called a key pair generator and we're going to get this from Key pair generator dot get instance of RSA this is going to get us an instance of a key generator that can go ahead and create RSA key pairs for us today we need to go ahead and initialize this we're going to use 2048 bits I'm going to go ahead and generate our key pair with keypair generator.generate key pair I accidentally typo this should be an uppercase p and now we're good to go if we have an exception we're going to go ahead and throw a new illegal State exception and at the bottom of the method we want to go ahead and return that key pair that we generated if it didn't generate properly it's just going to tone exception it shouldn't be an issue and then we can handle that exception later on so this is going to be used to of course go ahead and generate a key pair to go ahead and generate and encode and decoder jwts and with this we're going to need a model to actually store the key pair inside we can't just use key pair we're going to need something called an RSA Key Properties so what we're going to go and do is we're going to go ahead and make a new class inside our utils once again we're going to call this RSA Key Properties now our RSA Key Properties is going to be a component that we're going to want spring to generate for us so we're going to go ahead and say add component at the top and then inside we're going to have a couple of properties that we need to store firstly we're going to have a private RSA public key and then we're going to have a private RSA private key then we need to go ahead and create a special Constructor as you see this Constructor doesn't take any information however we are going to use the key generated utility to go ahead and generate an RSA key here and then store that into our public and private key variables now that we have our key pair we can go ahead and set these to our RSA public Keys the only thing that I have to keep in mind is that the key generator just returns a generic key so we're going to go ahead and cast these to the specific type of key rather be an RSA public key or an RSA private key now that we have our general Constructor set up let's go ahead and set up our Getters and Setters for the public and private Key Properties and that will go ahead and wrap up our essay Key properties and now before we go through and set up our jwts we need to actually add in the oauth2 resource server we're going to right click on our project go to Maven and open up the Palm file and then under the Spring Security starter we need to go ahead and add in a new dependency here and inside the dependency we're getting the group ID of org.spring framework dot boot then we're gonna need the artifact ID of spring Dash boot Dash starter dash oauth2-resource dash server now save vs code is probably going to tell us to go ahead and reload we can try and I spell dependency wrong it seems save and try again yes there we go and then even though vs code is going to try to do this I am going to go ahead and stop the application and go ahead and go up to my Maven and right click Maven and reload project just because last time vs code didn't do a great job now I'm gonna go ahead and go back into our security configuration and start setting up the things we need to create jwts now that we have oauth resource server all installed and everything we need to go ahead and set up our security configuration to go ahead and use jwts as well as create some beans to be able to actually encode and decode those so we're going to go to the top of our configuration class and the first thing we need to go ahead and do is we need to bring in a private final RSA key property we're going to call this keys and we need to go ahead and import our SAQ properties now this is obviously going to complain we're going to want to go ahead and auto wire this into a Constructor and this should get rid of that error and now whenever we go ahead and create this Bean of the security configuration is going to find the component called rsaq properties and go ahead and inject it in here next let's go ahead and go below our app being for security filter chain we're first going to go ahead and make a bean of type JWT decoder so to do this we're going to need to go ahead and use the app Bean annotation and below the app being annotation we're going to need a method which returns a JWT decoder let's go ahead and import our JWT encoder from security.org2 and then here we're going to need to go ahead and return a nimbus JWT decoder with a public key and we're going to get that public key from our keys property at the top of our security configuration we need to go ahead and import our Nimbus JWT decoder now this is going to be how we go ahead and take in our JWT and get the data out of it next we need another Bean of a JWT encoder so once again to do this we're going to need the app be an annotation and a method that returns a JWT encoder let's go ahead and import our JWT decoder from the oauth2.security and inside here we're going to step a couple things the first thing we need is a jwk and it's going to come from a new RSA key dot Builder with our public and private keys and now we need to go ahead and import our essay key from Jose then we need to go ahead and set up a jwk source and this is going to be called jwks this is going to be equal to a new immutable jwk set with our jwk inserted into a new jwk set now we have quite a few things to go ahead and import here so let's go ahead and grab our jwk set we'll go ahead and grab our security context which should come from Jose where you need the immutable jwk set which I spelled incorrectly slightly and we'll need the jwk set from Nimbus as well now we can go ahead and set up our final encoder which is going to take in the information that we just set up and return a new Nimbus JWT encoder once again we need to go ahead and return the JWT Nimbus encoder so now this is going to allow us to take in some information such as the token and the decoder we'll go ahead and get the data out of the token and the encoder will take some information bundle it up and sign it with our public and private key and then spit it out for us at the end now there is still one last thing that we need to go ahead and set up and that is to tell our Spring Security to actually use the oauth resource server and to read jwts so do that we need to go back up to a security filter chain and first we need to go ahead and get rid of our HTTP basic because we are no longer going to be authenticating that way we need to add oauth to Resource server and inside here we need to go ahead and pass or2 resource server configurer pulling Colin and we need to pass the method JWT we need to go ahead and import our oau 2 resource server configure hopefully exploded correctly it looks good and then we need to go ahead and set our session management to stateless so to do that we're going to go ahead and Dot session management and inside here we're gonna need a Lambda expression and what we want to say is we want to say session that session creation policy is going to be session creationpolicy dot stateless it'd be really nice if vs code didn't cover up what I'm writing let's go ahead and import our session policy and that should be good to go and we can go ahead and save so now what it's going to do is going to configure a oauth resource server for us and it's going to note to check for JWT tokens so now every time we send in a request that needs to be authenticated it's going to look inside the bear token authentication header and look for a token and then using the encoder and decoder it's going to know how to actually look for that and then using the public and private keys that we set up is going to know whether or not this is proper or not so now that we've got this all set up we need to go ahead and make our code be able to create our jvd tokens to send back to the client and actually decode them if we ever need that so now to actually use our jwts as we want we're going to need a new service to actually create these jwts so once again we'll go to our services package and hit the plus and now we're going to make a new service called token service at the top of our token service let's go ahead and throw the at service annotation and inside of our token service we're going to need a couple things Auto wired firstly we're going to Auto wire the private JWT encoder let's go ahead and import our JWT encoder then we're also going to need to go ahead and auto wire a JWT decoder we'll need to go ahead and import our jwtu decoder and once again you'd probably want to use Constructor injection here I'm just doing it the quick and simple way now we actually need a method to generate our JWT Force so we can send back to the user to do that we're going to go ahead and make a new public method which returns a string I'm going to call this generate JWT and we need to pass in this authentication object which we're going to get from Spring Security let's go ahead and import our authentication and this should come from Spring Security core not from Tomcat so for the time being I'm just going to return an empty string that way it's not complaining at us and it's not airing out and we're going to go ahead and start things now so the first thing that we're going to want to do is we're going to want to go ahead and take a snapshot of the time that way we know when we issued this token to do that we can go ahead and use an instant so we're going to say instant now is equal to instant dot now and this will go ahead and get the instant at the current time let's go ahead and import our instant so what we want to go and do now is we want to take all of our authorities and we're going to put them into one string that way we can put them inside of our JWT to do this we're going to go ahead and make a new string variable called scope then we're going to get the rolls out of our object that we passed into this method map over them with the stream API and then collect each string roll using collectors.joining with a space now I need to go ahead and import a couple things firstly we need granted Authority from our Spring Security and then we're also going to want collectors so all this is doing is it's looping through all the authorities inside of us us is going to be an authentication object which has all the roles from our user and then it's going to map through them and basically saying hey map it to a granted Authority if you went back to our model you would see that our roll goes ahead and implements granted Authority as you can see here that's why we're allowed to do this and it's just going to get the authority which for us is either going to be user admin and it's going to combine all of those into a single string delimited or spaced out by spaces next we need to go ahead and set up something called the JWT claim set and this is the information that the JWT is actually going to hold itself so to do this we're going to go ahead and say JWT claim set claims is equal to jwtclaimset.builder and we're going to pass in some more information from there so inside the Builder we need to pass in a few things first we need to pass is issuware which is just going to be self indicating that this specific back end or this specific service is issuing this token next we need to go ahead and say when we issued the set so we're going to use dot issued at and we're going to use this now instance that we created next we're going to go ahead and put in the subject this is going to be the person who the JWT is going towards and this is going to be auths.getname which is going to have the username of the person logging in then we need the claim which is basically going to be what information is holding and for us this is going to be the rules that we want and finally we need to call build issue that was being a little bit finicky there after we saved it all turned up so now we need to go ahead and use the JWT encoder and actually build a JWT token from this claim so now instead of returning an empty string what we're going to do is we're going to call JWT encoder dot encode they're going to pass in a static method call to JWT encoderparameters Dot from pass in those claims and then we're going to get the token from that JWT encoder so first let's go ahead and import our jvt token parameters so again let's walk through this we're using the JWT encoder to encode a new jbdt token and to encode this JWT token we're getting the information from our JWT encoder parameters from our claims list which has self Windows issued the subject name and this could technically be any object I believe this doesn't have to be a string or I guess it does have to be a string I'm wrong so this could be the the person's name it could be something else if you want but typically I think it's using the user's username we can have multiple claims so you can put the scope you can put some other things here so what are they allowed to use and some other information if you want you can put the entire user in there if you want I wouldn't suggest that but you could and then we need to build it so this is our claims we're building a JWT token based on that then whenever we call get token value this is going to spit out the string value that we actually pass back to the user on the front end so now that we have this complete what we could actually do is go ahead and create a response for a login because we don't just have to pass back the user we're going to need to pass back a user and the string JWT so what we'll do is we'll go up to our models package hit new we'll go ahead and make a login response dto and inside of our login response dto this is not going to be saved to the database or anything like that we're just going to have a couple of things so once again we'd probably want a user dto or something along those lines instead we'll go ahead and just add in a private application user we're also going to go ahead and add in a private string JWT so obviously the user is the person that was logged in in case they need the information and the JWT is going to be obviously the JWT now theoretically if we wanted to we don't have to send back the user sometimes whenever I log in though typically if you're doing something like react or something you want to put the user into like a user slice or something along those lines because they logged in they have the new information if you weren't worried about that and all you want to do is send back a JWT you can completely just ignore the step and not do it whatsoever so now we need to go ahead and set up a couple of our Constructors we'll also go ahead and set up our Getters and Setters as well and if you guys want to and know how to definitely go ahead and auto generate these now that our simple response GTOs setup we can actually go about logging in the user and to log in the user we're going to go back into our authentication Service and set up a login message so back inside of our authentication Service at the top we're going to go ahead and auto wire a couple more things first thing we're going to need is a private authentication manager and this is going to determine whether or not we want to go ahead and make a JWT token and that's going to import our authentication manager and this is going to grab the instance that we set up inside of our configuration and then we also need the token service that way after we know that we're authenticated to log in we can actually go ahead and generate that token for the user so let's go ahead and say Auto wired private token service token service now we can go ahead and save that now let's go ahead and start working on our login method so to be able to log into user we're going to want to go ahead and create a public method which Returns the login response dto and takes in the usage so username and password let's go ahead and import our login response dto and for the time being we'll return no so that it stops airing out so the purpose of this method is it's going to take the authentication manager it's going to look for a username and password and make sure that they are proper is going to generate something called an authentication token send that over to our token service and generate the token and then spit it out what we're going to want to do is we're going to want to start out the try catch because our authentication manager might throw an exception so let's go ahead and do that the exception that might be thrown is called an authentication exception let's go ahead and import our authentication exception and this is going to come from org.spring framework and it's probably going to complain for the time being just because obviously this is no bueno if this occurs you'd probably want to rethrow some custom exceptions saying hey this doesn't work make sure it's a 401 or something along those lines however all we're going to do is we're going to go ahead and just return a new login response object with null and JWT token as empty let's go ahead and get rid of our old return no it's going to complain for a second again but it's fine now inside of the drive we want to go ahead and attempt authenticating with the authentication manager so we're going to make a new authentication object and that's going to be equal to authentication manager.authenticate and we want a new username password authentication token based off our username and password let's go ahead and make sure we import the correct authenticate this is going to come from Spring Security core and let's go ahead and grab our username and password authentication token so what this is basically going to do is whenever we send in a request for login user is going to pass in the username password to this authentication manager and it's going to use our user Detail Service that we set up earlier grab the user and that username doesn't exist it's going to throw an exception or if the username does exist and then the password exists it'll create the token otherwise its own exception so basically long story short all it's doing is it's going to use our authentication manager to use a user Detail Service to find the user check their password if everything's proper it's going to spit out this new token for us to send called auth and authentication is just a generic token or generic authentication object so this new username password authentication token is a more specific version of authentication or token service method took in and off and this is where it's coming from so now we need to go ahead and get our token by making a new string called token and then call the token service.generate JWT so if our user logs in successfully their username passwords correct the authentication manager finds the username and password it's going to generate a new JWT token and what we want to go ahead and do is return a new login response object with that user as well as the token so let's go ahead and return a new login response GTO where you actually want to send back the entire application user so we're going to use our user repository.find user by username and then pass in the token that we generated as well there we go once again if everything works properly we'll generate our authentication token we'll go ahead and send that token over to our JWT and then we'll go ahead and return back the user as well as the token theoretically what we could have done is we could have done the checking for the auth with the authentication manager and then we could have just returned passed in the whole user here and generated that stuff but from the documentation everything else I've seen this is how they want you to do this we can go ahead and save this and now all we need to do is go ahead and set up the endpoint for slash login and we can go ahead and attempt to log in to see if we can get a JWT token we need to go back into our controller then and then into our authentication controller so once again we're going to need another post mapping this time it's going to go to slash login and below a post mapping we're going to make a new public method which returns a login response object we're just going to cheat a little bit we're going to use the request body of type registration dto well bro I need to go ahead and import our login response GTO and typically what would happen here is you would have different dtos for registration and login our object is so simple that they both just taken a username and password a lot of time whenever you're registering a user you'll probably take in the username password email first name last name so on and so forth and then you'll probably still have some hidden details such as like rules and other things like that that don't necessarily need to be sent across and then typically your login dto will most likely just be used to name and password so our registration dto is more like a login dto but it is what it is this is going to be a very simple method all we have to do is go ahead and return authentication Service DOT log in user and then pass in that username password from the body and as simple as that we can go and save and now we can go and hop back into Postman we'll have to re-register our user because we restarted the server several times let's go ahead and register Ethan again and then let's go ahead and log in and see if we can get a JWT so once again we'll have to go ahead and register Ethan so we have our awesome register and we have our username and password in the Json like we need if we go ahead and send we see we get a 200 back and we got all the information about Ethan so now we're going to want to do is go back into the top hit the new icon and make a new post request to http colon slash localhost corn 8000 slash auth slash login now inside of our slash login we need a body of Json so we'll say raw Json and this also needs a username so this is going to be Ethan and it needs a password which would just be password so now if we go ahead and try to log in it should send back 200 with our newly created JWT token as you see we have our user back once again you wouldn't want to send back all this information maybe just using a password or something we also have this JW team so now if we try to access the slash user as normal we should get a 401 unauthorized because we're not passing in our JWT token as you see for one unauthorized what we need to go ahead and do is instead of basic auth we have to say Bearer token and then the bear token is going to be this JWT that we generated so go ahead and copy this guy and paste it into our bear token which every time you add in the bear token it just holds on to the last one so I that's why that's there for my Twitter series if I send we see a 200 okay user access level now the only issue that we have here is that if we go ahead and do admin we know that our user Eason is only a user but if we go ahead and use a git for admin you'll see they also have admin level access so the last thing that I want to go and do for this quick tutorial is to show you guys how we can actually lock down different routes and different endpoints by actual rules unfortunately this is not the easiest thing to do and it's kind of messy just because of the way that we had to store things into our GWT but let's go ahead and hop back into our authentication configuration I'll show you guys how to do this so once again inside of our security configuration we need to go ahead and make one more bean and this is going to be a JWT authentication converter being once again we'll need the app being annotation and then below it we'll need a method that returns a JWT authentication converter let's go ahead and import this JWT authentication converter because of what we named our roles in our table we just called them roll we're going to convert all of the names inside of the claim roles into roll underscore role so for example if it's a role user instead of just having the role of user we need to change this to roll underscore user instead now to do this we're going to need something called a JWT granted authorities converter so to do that we're going to go ahead and make a new object called a JWT granted authorities converter by calling new jwte granted authorities converter then we're going to go ahead and set the name of the claim that this JWT granted Authority converters can be looking for in our case we set the roles of our user in a claim name called roles so we're going to go ahead and use JWT granted Authority converter dot set Authority's claim name equal to rules now we need to go ahead and tell the converter what we want to rename each role into the Spring Security convention is to use roll underscore this is why we obviously named our rules it's like user or admin because inside of our table we don't want roll underscore everything so this is why we need to go ahead and convert these so to convert these we're going to go ahead and say JWT grants an authorities converter dot set Authority prefix to rule underscore now that we have told our JWT granted authorities converter what we wanted to look for and how to rename all of our rules we need to go ahead and create a new JWT authentication converter to go ahead and call our JWT granted authorities converter and this will go ahead and actually take those roles append roll name and then return a new Authority for us to use so to do that we're going to go ahead and create a new JWT authentication converter thank you now that we have our JWT authentication converter now we need to tell Spring Security what and how we are converting these JWT authorities so to do that we're going to go ahead and say jwtconverter.set JWT granted authorities converter with that converter that we set above now all we need to do is go ahead and return the JWT converter so just to recap here because it is a little bit confusing currently whenever we create a JWT token that gets decoded by the backend it's going to have a claim called roles the claim with roles is going to hold all the roles that this user has so basically are they a user are they an admin are they employee are they a guest so on and so forth the problem with this is that by default what spring is going to be looking for whenever it's decoding these and authenticating people is it's going to look for the role underscore So currently our roles do not have role underscore so then Spring Security will not know how to match a user against the rules so this JWT granted authorities converter is going to go through look at that token that it created and convert all of our roles inside of our roll claim into roll underscore and then this JWT converter will go ahead and spit out a new token That Way Spring Security can be able to actually tell what's going on so to be able to actually use this we have to set this up inside the oauth2 resource server inside our filter chain we're also going to do a little bit of refactoring inside the filter chain anyway so let's go ahead and scroll up and take a look at that our csrf disabled is fine and our authorized HTTP requests are going to need to be changed a little bit we still want our request matches to slash permit all however now instead of just authenticating everything we want to go ahead and list out some of our rules so first we want to go ahead and try to say auth.request matchers we want to try to match the slash admin route with any other route after that so any route matching slash admin slash we want the user to have a row of admin so what we can go ahead and say it says has Rule and we want to make sure they have role of admin so this part was really confusing to me whenever I was first trying to figure this out the has roll part is only going to look for uppercase admin however the authentication manager is going to look for a roll underscore admin this is why we had to set up this JWT encoder before next we want to go ahead and set up our user route let's go ahead and add an author request matchers for slash user so now for any route and get out of here please for any route under the user tree we want the user to either have a rule of admin or user so for this we can say has any role and then here we can say either admin or type user so now admins or users can access this but only admins can access the slash admin routes after this we want all other of our requests to be authenticated now to actually be able to set up our JWT to be read properly we have to set up something in the oauth2 resource server last time I attempted this it was being a little bit finicky so we're going to see if it wants to work otherwise I'll do it the other way so we're going to go ahead and get rid of this JWT from in here and we're going to add dot JWT and under that we're going to add dot JWT authentication converter and we're going to pass in the jwg authentication converter that we set up below and now this is the issue I found before for some reason it doesn't like the session management and even if I dot add Dot and here it still doesn't like the sessions management so what we're going to go and do is we're going to separate these so we're going to say instead of return here we're going to say http.csrf blah blah blah we're going to add a semicolon then we're going to add in HTTP once again so HTTP and then dot oauth2 resource server and then we're going to add a semicolon and then we're going to add http dot session management and then finally we'll return http.build so I don't know why it's like this typically you can add Dot and I haven't figured out why it does this we can save now and it should go ahead and work for us I have an extra parenthesis actually I need a semicolon at the end and save and now it should return the bill HTTP we can also go ahead and fix up this stuff to make it look a little bit prettier but there we go now if we head back into Postman and since we restarted application we'll once again need to go ahead and register Ethan so let's go ahead and register ethernet password we can go ahead and log in Ethan with password and now Ethan has a new token we can go ahead and copy this new token and we go into slash user slash and put in Ethan's new token and send the request we should see user level access if we try to access admin with Ethan's token it should say access denied or 401 403 Forbidden because we don't have authorization a little bit different but it's because we don't have the proper authorization however if we go ahead and add login to admin now we can see we have our admin our admin has a JWT token let's go ahead and copy and paste this and then we can go ahead and paste in that admin token inside of here and send and now you see admins have admin level access users have user level access and this is basically how we can set up our very basic application that's going to be it for this video I want to thank you all for watching you've gone to this point this was an absolute Behemoth of a video and it also took me literally hours and hours and days of recording of researching of editing and everything like that to get the video all complete so if you made this point please go ahead and hit that like button to show some support and if you really enjoyed the content go ahead and please subscribe if you do subscribe then I'll go ahead and note that you guys do want more content like this if you have an issue for watching more coding content I do have an entire series called let's build Twitter if you haven't seen it yet where I'm going through and building Twitter from the ground up using spring boot spring data react and Redux so I think you guys would really enjoy that once again I appreciate all the support this has been Ethan encoder have a great day everybody and peace out
Info
Channel: Unknown Koder
Views: 53,641
Rating: undefined out of 5
Keywords: Java, Java Programming Language, Spring, Spring Boot, Spring Boot 3, Spring Boot 3 Framework, Spring Web, Spring Web 6, Spring Data JPA, Spring Data, Spring Security, Spring Security 6, Spring Security 6 Tutorial, Spring Security 6 Database Access, Spring Security 6 JWT, Spring Security 6 Login, OAuth2ResourceServer, JWTs, JSON Web Tokens, Stateless API, Spring Security Authenticated Backend, Spring Security 6 Role Based Authorization, Spring Security 6 Password Encryption
Id: TeBt0Ike_Tk
Channel Id: undefined
Length: 104min 37sec (6277 seconds)
Published: Fri Apr 07 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.