Asp.net core 如何将已授权的用户重定向回identity server 4.NET CORE中的上一页?

Asp.net core 如何将已授权的用户重定向回identity server 4.NET CORE中的上一页?,asp.net-core,.net-core,asp.net-core-mvc,identityserver4,Asp.net Core,.net Core,Asp.net Core Mvc,Identityserver4,下面是在身份验证服务器和客户端计算机中添加的代码 如果需要更多信息,请发表评论 StartUp.cs--身份验证服务器 public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); var builder = services.AddIdentityServer(options => {

下面是在身份验证服务器和客户端计算机中添加的代码 如果需要更多信息,请发表评论

StartUp.cs--身份验证服务器

public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        var builder = services.AddIdentityServer(options =>
        {
            options.EmitStaticAudienceClaim = true;
        })
            .AddInMemoryIdentityResources(Config.IdentityResources)
            .AddInMemoryApiScopes(Config.ApiScopes)
            .AddInMemoryClients(Config.Clients)
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>() 
            /*.AddProfileService<ProfileService>()*/;

        builder.AddDeveloperSigningCredential();



        services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
        //services.AddTransient<IProfileService, ProfileService>();
    }
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        try
        {
            UserInfo user = await GetUserDetails(context.UserName, context.Password).ConfigureAwait(false);
            if (user != null && string.IsNullOrEmpty(user.ErrorMessage))
            {
                //set the result
                context.Result = new GrantValidationResult(
                    subject: user.UserId.ToString(),
                    authenticationMethod: "custom",
                    claims: GetUserClaims(user));
                return;
            }

            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, user.ErrorMessage);
            return;
        }
        catch (Exception ex)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Invalid username or password");
        }
    }

    //build claims array from user data
    public static Claim[] GetUserClaims(UserInfo user)
    {
        return new Claim[]
        {
        new Claim("user_id", user.UserId.ToString() ?? ""),
        new Claim(JwtClaimTypes.Name, (!string.IsNullOrEmpty(user.FirstName) && !string.IsNullOrEmpty(user.Surname)) ? (user.FirstName + " " + user.Surname) : ""),
        new Claim(JwtClaimTypes.GivenName, user.FirstName  ?? ""),
        new Claim(JwtClaimTypes.FamilyName, user.Surname  ?? ""),
        new Claim(JwtClaimTypes.Email, user.Email  ?? "")
        };
    }
}
ResourceOwnerPasswordValidator.cs——身份验证服务器

public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        var builder = services.AddIdentityServer(options =>
        {
            options.EmitStaticAudienceClaim = true;
        })
            .AddInMemoryIdentityResources(Config.IdentityResources)
            .AddInMemoryApiScopes(Config.ApiScopes)
            .AddInMemoryClients(Config.Clients)
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>() 
            /*.AddProfileService<ProfileService>()*/;

        builder.AddDeveloperSigningCredential();



        services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
        //services.AddTransient<IProfileService, ProfileService>();
    }
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        try
        {
            UserInfo user = await GetUserDetails(context.UserName, context.Password).ConfigureAwait(false);
            if (user != null && string.IsNullOrEmpty(user.ErrorMessage))
            {
                //set the result
                context.Result = new GrantValidationResult(
                    subject: user.UserId.ToString(),
                    authenticationMethod: "custom",
                    claims: GetUserClaims(user));
                return;
            }

            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, user.ErrorMessage);
            return;
        }
        catch (Exception ex)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Invalid username or password");
        }
    }

    //build claims array from user data
    public static Claim[] GetUserClaims(UserInfo user)
    {
        return new Claim[]
        {
        new Claim("user_id", user.UserId.ToString() ?? ""),
        new Claim(JwtClaimTypes.Name, (!string.IsNullOrEmpty(user.FirstName) && !string.IsNullOrEmpty(user.Surname)) ? (user.FirstName + " " + user.Surname) : ""),
        new Claim(JwtClaimTypes.GivenName, user.FirstName  ?? ""),
        new Claim(JwtClaimTypes.FamilyName, user.Surname  ?? ""),
        new Claim(JwtClaimTypes.Email, user.Email  ?? "")
        };
    }
}
登录逻辑---

[HttpPost]
[ValidateAntiForgeryToken]
公共异步任务登录(LoginInputModel模型,字符串按钮)
{
//检查我们是否在授权请求的上下文中
var context=await\u interaction.GetAuthorizationContextAsync(model.ReturnUrl);
如果(按钮==“重置”)
{
返回重定向(“ResetPasswordWithoutCode”);
}
其他的
{
//用户单击了“取消”按钮
如果(按钮==“取消”)
{
if(上下文!=null)
{
//如果用户取消,则将结果发送回IdentityServer,就像他们
//拒绝同意(即使该客户不需要同意)。
//这将向客户端发回拒绝访问的OIDC错误响应。
wait_interaction.DenyAuthorizationAsync(上下文,AuthorizationError.AccessDenied);
//我们可以信任model.ReturnUrl,因为GetAuthorizationContextAsync返回了非null
if(context.IsNativeClient())
{
//客户端是本机的,因此此更改将
//返回的响应是为最终用户提供更好的用户体验。
返回此.LoadingPage(“重定向”,model.ReturnUrl);
}
返回重定向(model.ReturnUrl);
}
其他的
{
//因为我们没有有效的上下文,所以我们只需返回主页
返回重定向(“~/”);
}
}
if(ModelState.IsValid)
{
ResourceOwnerPasswordValidationContext context1=新ResourceOwnerPasswordValidationContext();
context1.UserName=model.UserName;
context1.Password=model.Password;
//根据内存存储验证用户名/密码
wait_resourceOwner.ValidateAsync(context1);
if(context1.Result.Subject!=null&&context1.Result.Subject.Identity.IsAuthenticated)
{
var user=await ResourceOwnerPasswordValidator.GetUserDetails(model.Username,model.Password).ConfigureAwait(false);
wait_events.RaiseAsync(新的userloginsAccessEvent(user.Username,user.UserId,user.Username,clientId:context?.Client.clientId));
//仅当用户选择“记住我”时才在此处设置显式过期。
//否则,我们依赖于cookie中间件中配置的过期。
AuthenticationProperties props=null;
if(AccountOptions.AllowRememberLogin&&model.RememberLogin)
{
props=新的AuthenticationProperties
{
ispersist=true,
ExpiresUtc=DateTimeOffset.UtcNow.Add(AccountOptions.rememberLoginDuration)
};
};
//发出具有主题ID和用户名的身份验证cookie
var isuser=new IdentityServerUser(user.UserId)
{
DisplayName=user.Username
};
等待HttpContext.SignInAsync(isuser,props);
if(上下文!=null)
{
if(context.IsNativeClient())
{
//客户端是本机的,因此此更改将
//返回的响应是为最终用户提供更好的用户体验。
返回此.LoadingPage(“重定向”,model.ReturnUrl);
}
//我们可以信任model.ReturnUrl,因为GetAuthorizationContextAsync返回了非null
返回重定向(model.ReturnUrl);
}
//请求本地页面
if(Url.IsLocalUrl(model.ReturnUrl))
{
返回重定向(model.ReturnUrl);
}
else if(string.IsNullOrEmpty(model.ReturnUrl))
{
返回重定向(“~/”);
}
其他的
{
//用户可能单击了恶意链接-应记录
抛出新异常(“无效返回URL”);
}
}
wait_events.RaiseAsync(新用户登录失败事件(model.Username,“无效凭据”,clientId:context?.Client.clientId));
ModelState.AddModelError(string.Empty,AccountOptions.InvalidCredentialsErrorMessage);
}
//出了问题,用错误显示表单
var vm=等待BuildLoginViewModelAsync(模型);
返回视图(vm);
}
}
我正在调用一个webapi来检查凭据,并返回有关用户的信息,如名字和姓氏

重定向URI-https://localhost:44356/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DTestIdpApp%26redirect_uri%3Dhttps%253A%252F%252Flocalhost%253A44335%252Fsignin-oidc%26响应类型%3Dcode%26范围%3Dopenid%2520配置文件%26代码挑战%3DLEZALWC8SHZZ6LGUSDEUPR974CLSUSYVPXDNMBWOE%26代码挑战方法%3DS256%26响应模式%3Dform_post%26当前值%3D637360236231259886.mmixnjlhodmtztjhy00yzuzltliyjmtzwjmzm3zjrim2vlzm
if (this.User.Identity.IsAuthenticated)
{
    return Redirect(returnUrl);
}