public async Task <string> GetGeneralApiToken(HttpContext httpContext) { var web_access_token = await httpContext.GetTokenAsync("access_token"); JwtSecurityToken jwtSecurityToken = (new JwtSecurityTokenHandler()).ReadToken(web_access_token) as JwtSecurityToken; string cacheKey = $"CurrentUserToken_{jwtSecurityToken.Claims.First(claim => claim.Type == "sub").Value}_{jwtSecurityToken.Claims.First(claim => claim.Type == "auth_time").Value}"; string general_api_token = await RedisHelper.GetAsync <string>(cacheKey); if (string.IsNullOrEmpty(general_api_token)) { general_api_token = jwtSecurityToken.Claims.First(claim => claim.Type == "general_api_token").Value; } GeneralApiToken generalApiToken = JsonConvert.DeserializeObject <GeneralApiToken>(general_api_token); if (generalApiToken.ExpiresAt > DateTime.UtcNow) { return(generalApiToken.AccessToken); } else { HttpClient client = httpClientFactory.CreateClient("GetGeneralApiToken"); var disco = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest { Address = Configuration["IdentityService:Authority"], Policy = { RequireHttps = false } }); if (disco.IsError) { return(null); } var tokenResponse = await client.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = disco.TokenEndpoint, ClientId = "GeneralApiClient", ClientSecret = "P@ssw0rd", RefreshToken = generalApiToken.RefreshToken, Scope = "GeneralServiceApi offline_access" }); if (tokenResponse.IsError) { return(null); } generalApiToken = new GeneralApiToken() { ExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn), AccessToken = tokenResponse.AccessToken, RefreshToken = tokenResponse.RefreshToken }; await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(generalApiToken)); return(generalApiToken.AccessToken); } }
public async Task <IActionResult> Login(LoginInputModel model, string button) { // check if we are in the context of an authorization request var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl); // the user clicked the "cancel" button if (button != "login") { if (context != null) { // if the user cancels, send a result back into IdentityServer as if they // denied the consent (even if this client does not require consent). // this will send back an access denied OIDC error response to the client. await _interaction.GrantConsentAsync(context, ConsentResponse.Denied); // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null if (await _clientStore.IsPkceClientAsync(context.ClientId)) { // if the client is PKCE then we assume it's native, so this change in how to // return the response is for better UX for the end user. return(View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl })); } return(Redirect(model.ReturnUrl)); } else { // since we don't have a valid context, then we just go back to the home page return(Redirect("~/")); } } if (ModelState.IsValid) { HttpClient client = _httpClientFactory.CreateClient(); var disco = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest { Address = Configuration["IdentityService:Authority"], Policy = { RequireHttps = false } }); if (disco.IsError) { throw new Exception(disco.Error); } var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = disco.TokenEndpoint, ClientId = "GeneralApiClient", ClientSecret = "P@ssw0rd", UserName = model.Username, Password = model.Password, Scope = "GeneralServiceApi offline_access" }); if (!tokenResponse.IsError) { await _events.RaiseAsync(new UserLoginSuccessEvent("", model.Username, "")); // only set explicit expiration here if user chooses "remember me". // otherwise we rely upon expiration configured in cookie middleware. AuthenticationProperties props = null; if (AccountOptions.AllowRememberLogin && model.RememberLogin) { props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration) }; } ; GeneralApiToken generalApiToken = new GeneralApiToken() { ExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn), AccessToken = tokenResponse.AccessToken, RefreshToken = tokenResponse.RefreshToken }; Claim tokenClaim = new Claim("general_api_token", JsonConvert.SerializeObject(generalApiToken)); List <Claim> listClaim = new List <Claim>() { tokenClaim }; // issue authentication cookie with subject ID and username await HttpContext.SignInAsync(model.Username, props, listClaim.ToArray()); if (context != null) { if (await _clientStore.IsPkceClientAsync(context.ClientId)) { // if the client is PKCE then we assume it's native, so this change in how to // return the response is for better UX for the end user. return(View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl })); } // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null return(Redirect(model.ReturnUrl)); } // request for a local page if (Url.IsLocalUrl(model.ReturnUrl)) { return(Redirect(model.ReturnUrl)); } else if (string.IsNullOrEmpty(model.ReturnUrl)) { return(Redirect("~/")); } else { // user might have clicked on a malicious link - should be logged throw new Exception("invalid return URL"); } } else { await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials")); string errMsg = tokenResponse.Error + ":" + (string.IsNullOrEmpty(tokenResponse.ErrorDescription) ? "" : tokenResponse.ErrorDescription); ModelState.AddModelError(string.Empty, errMsg); } } // something went wrong, show form with error var vm = await BuildLoginViewModelAsync(model); return(View(vm)); }