Download the Chinook database BAK file for this part of the workshop in the GitHub repo. The file is a backup so we will restore it to where you have MSSQL 2019 installed.
#RUN SQL SCRIPT TO ADD IDENTITY TABLES TO EXISTING CHINOOK DB
If you don't have MSSQL 2019 installed you can update your Chinook database by running this SQL script against your database to add the tables needed for Identity for this part of the workshop.
#UPDATE DBCONTEXT TO DESCEND FROM IDENTITYDBCONTEXT
#ADD REGISTER ACTION AND LOGIN ACTION TO HOME CONTROLLER IN API POJECT
[Route("api/[controller]")][ApiController][EnableCors("CorsPolicy")]publicclassHomeController:ControllerBase{privatereadonlyILogger<HomeController> _logger;privatereadonlyUserManager<IdentityUser> _userManager;privatereadonlyJwtConfig _jwtConfig;publicHomeController(ILogger<HomeController> logger,UserManager<IdentityUser> userManager,IOptionsMonitor<JwtConfig> optionsMonitor){
_logger = logger;
_userManager = userManager;
_jwtConfig = optionsMonitor.CurrentValue;}[HttpGet]publicIActionResultIndex(){returnOk();}[HttpPost,Route("Register")]publicasyncTask<ActionResult<RegistrationResponse>>Register([FromBody]RegisterModel user){// Check if the incoming request is validif(ModelState.IsValid){// check i the user with the same email existvar existingUser =await _userManager.FindByEmailAsync(user.Email);if(existingUser !=null)returnBadRequest(newRegistrationResponse{
Result =false,
Errors =newList<string>{"Email already exist"}});var newUser =newIdentityUser{ Email = user.Email, UserName = user.Email };var isCreated =await _userManager.CreateAsync(newUser, user.Password);if(isCreated.Succeeded){var jwtToken =GenerateJwtToken(newUser);returnOk(newRegistrationResponse{
Result =true,
Token = jwtToken
});}returnnewJsonResult(newRegistrationResponse{
Result =false,
Errors = isCreated.Errors.Select(x => x.Description).ToList()}){ StatusCode =500};}returnBadRequest(newRegistrationResponse{
Result =false,
Errors =newList<string>{"Invalid payload"}});}[HttpPost,Route("Login")]publicasyncTask<ActionResult<RegistrationResponse>>Login([FromBody]LoginModel user){if(ModelState.IsValid){// check if the user with the same email existvar existingUser =await _userManager.FindByEmailAsync(user.Email);if(existingUser ==null){// We dont want to give to much information on why the request has failed for security reasonsreturnBadRequest(newRegistrationResponse(){
Result =false,
Errors =newList<string>(){"Invalid authentication request"}});}// Now we need to check if the user has inputed the right passwordvar isCorrect =await _userManager.CheckPasswordAsync(existingUser, user.Password);if(isCorrect){var jwtToken =GenerateJwtToken(existingUser);returnOk(newRegistrationResponse(){
Result =true,
Token = jwtToken
});}else{// We dont want to give to much information on why the request has failed for security reasonsreturnBadRequest(newRegistrationResponse(){
Result =false,
Errors =newList<string>(){"Invalid authentication request"}});}}returnBadRequest(newRegistrationResponse(){
Result =false,
Errors =newList<string>(){"Invalid payload"}});}privatestringGenerateJwtToken(IdentityUser user){// Now its ime to define the jwt token which will be responsible of creating our tokensvar jwtTokenHandler =newJwtSecurityTokenHandler();// We get our secret from the appsettingsvar key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);// we define our token descriptor// We need to utilise claims which are properties in our token which gives information about the token// which belong to the specific user who it belongs to// so it could contain their id, name, email the good part is that these information// are generated by our server and identity framework which is valid and trustedvar tokenDescriptor =newSecurityTokenDescriptor{
Subject =newClaimsIdentity(new[]{newClaim("Id", user.Id),newClaim(JwtRegisteredClaimNames.Sub, user.Email),newClaim(JwtRegisteredClaimNames.Email, user.Email),// the JTI is used for our refresh token which we will be convering in the next videonewClaim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())}),// the life span of the token needs to be shorter and utilise refresh token to keep the user signedin// but since this is a demo app we can extend it to fit our current need
Expires = DateTime.UtcNow.AddHours(6),// here we are adding the encryption alogorithim information which will be used to decrypt our token
SigningCredentials =newSigningCredentials(newSymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha512Signature)};var token = jwtTokenHandler.CreateToken(tokenDescriptor);var jwtToken = jwtTokenHandler.WriteToken(token);return jwtToken;}}