代码之家  ›  专栏  ›  技术社区  ›  Kamran Khan

部署时Jwt令牌访问群体验证失败

  •  0
  • Kamran Khan  · 技术社区  · 4 年前

    我使用ASPNET core 5.0作为前端和后端API。它在本地机器上运行得很好,但我部署了前端和API应用程序,这总是导致观众验证失败。这是我正在使用的代码。

    "Jwt": {
        "Issuer": "RestaurantPortal",
        "Audience": "http://mansoor0786-001-site1.ctempurl.com/",
        "Key": "ASAscethtCVdAQAAAAEAACcQAAAAEDhnGasldjaslkjdleEnGunGWR4Z79AvrtgIjYXhcWZx4OqpvWbsdsdsdSafcV/ZuPw25KbhKWhg1SIXXU2Ad7maaGAk******"
      },
    

    我将其保存在前端和API应用程序的应用程序设置中。下面是API启动代码

     services.AddAuthorization(options =>
            {
                options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser().Build();
            });
            services.AddAuthentication()
           .AddCookie()
           .AddJwtBearer(config =>
           {
               config.TokenValidationParameters = new TokenValidationParameters()
               {
                   ValidIssuer = JwtConfiguration.JWTIssuer,
                   ValidAudience = JwtConfiguration.JWTAudience,
                   IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConfiguration.JWTKey)),
                   ClockSkew = TimeSpan.Zero
               };
           });
    

    下面是当用户想要登录时,我在API端进行的验证。

    public bool ValidateToken(string token)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            try
            {
                tokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidIssuer = JwtConfiguration.JWTIssuer,
                    ValidAudience = JwtConfiguration.JWTAudience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConfiguration.JWTKey)),
                    ClockSkew = TimeSpan.Zero
                }, out SecurityToken validatedToken);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
    

    在本地,它工作正常,但当部署这两个应用程序时,它会给我一个错误,当我尝试登录时,它不允许我登录系统。下面是API和前端应用程序的URL。这是我生成令牌的地方

     public string GenerateAccessToken(IEnumerable<Claim> claims)
            {
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConfiguration.JWTKey));
                var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
                var tokeOptions = new JwtSecurityToken(
                    issuer: JwtConfiguration.JWTIssuer,
                    audience: JwtConfiguration.JWTAudience,
                    claims: claims,
                    expires: DateTime.Now.AddHours(24),
                    signingCredentials: signinCredentials
                );
                var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
                return tokenString;
            }
    

    在这种情况下,配置从appSettings获取信息。json

    public static class JwtConfiguration
        {
            public static readonly string JWTIssuer = Utils._config["Jwt:Issuer"];
            public static readonly string JWTAudience = Utils._config["Jwt:Audience"];
            public static readonly string JWTKey = Utils._config["Jwt:Key"];
        }
    

    这是我登录用户时的回复

     if (apiResponseModel != null && apiResponseModel.Data != null && apiResponseModel.Data.Status == 1)
                    {
                        var claims = new List<Claim>
                         {
                            new Claim(AuthKeys.AccessToken, apiResponseModel.Data.AccessToken),
                            new Claim(AuthKeys.RefreshToken, apiResponseModel.Data.RefreshToken)
                         };
                        var claimsIdentity = new ClaimsIdentity(
                          claims, CookieAuthenticationDefaults.AuthenticationScheme);
                        var authProperties = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc = DateTime.UtcNow.AddMinutes(30),
                        };
                        await HttpContext.SignInAsync(
                          CookieAuthenticationDefaults.AuthenticationScheme,
                          new ClaimsPrincipal(claimsIdentity),
                          authProperties);
                        if (apiResponseModel.Data.RoleName == UserRole.Roles.Customer.GetEnumDescription())
                        {
                            return RedirectToAction("index", "Home");
                        }
                        return RedirectToAction("index", "dashboard");
                    }
    

    之后,它重定向到仪表板索引页面,我在其中编写了base controller,并在basecontroller的顶部添加了属性,该属性执行以下操作。

    [ServiceFilter(typeof(JWT_Authentication))]
        public class BaseController : Controller
        {
            public readonly IOptions<AppSettingDTO> _appSetting;
            protected readonly IUserProfileInfo _userService;
            public readonly IHttpContextAccessor _httpContextAccessor;
            protected readonly IHttpNetClientService _apiService;
    
            public BaseController(IOptions<AppSettingDTO> AppSetting, IHttpNetClientService HttpService, IUserProfileInfo UserInfo, IHttpContextAccessor HttpContext)
            {
                _appSetting = AppSetting;
                _apiService = HttpService;
                _userService = UserInfo;
                _httpContextAccessor = HttpContext;
    
            }
    
        }
    

    这是我的JWT_认证

    public class JWT_Authentication : ActionFilterAttribute
        {
            private readonly IHttpContextAccessor _httpContextAccessor;
            protected readonly IUserProfileInfo _userService;
            public JWT_Authentication(IHttpContextAccessor HttpContext, IUserProfileInfo UserInfo)
            {
                _httpContextAccessor = HttpContext;
                _userService = UserInfo;
            }
            public override void OnActionExecuting(ActionExecutingContext context)
            {
                string actionName = context.RouteData.Values["Action"].ToString().ToLower();
                string controllerName = context.RouteData.Values["Controller"].ToString().ToLower();
    
                if (
                    controllerName != "account" && actionName != "logout")
                {
                    string accessTokens = _userService.GetToken(_httpContextAccessor);               
                    if (!_userService.ValidateToken(accessTokens))
                    {
    
                    }
                    else
                    {
                        return;
                    }
                    context.Result = new RedirectToRouteResult(new RouteValueDictionary(){
                                { "action", "LogOut" },
                                { "controller", "Account" }
                            });
                    return;
                }
            }
        }
    

    美国石油学会

    http://mansoor00786-001-site1.gtempurl.com/

    前端

    http://mansoor0786-001-site1.ctempurl.com/

    我正在从前端应用程序调用登录API,该应用程序也在asp net core 5.0中,但由于验证失败,这是因为受众原因,它没有将我登录到仪表板。

    0 回复  |  直到 4 年前
        1
  •  0
  •   Gordon Khanh Ng.    4 年前

    据我所知,这里是我发现的一些要点

    调用时不会抛出异常 ValidateToken

    因为我们把它放在试抓块上,所以它会扔到哪里 audience validation failure ? 它不能在部署期间出现,因为catch块在任何地方都没有日志记录支持,因此,这可能只是您的假设。在注销后,生产状态下的行为应始终重定向到登录页面。

    MVC项目处理Jwt令牌的方式很麻烦

    当我们手工制作Jwt令牌并自己验证它们时,比如在相同的设置下验证失败(发卡机构、观众等)不应该存在。如果这对客户来说没问题,那就要有信心,记录那些从生产状态出发的人。

    对于当前的方法,我们可以验证Jwt令牌并限制它们访问我们的资源,但是 HttpContext.User 对象仍然为空,因此授权过程基本上无法使用。

    取而代之的是,如何考虑编写我们自己的认证方案?

    这里可能有什么问题?

    public class JWT_Authentication : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //... Some upper process
            if (!_userService.ValidateToken(accessTokens))
            {
                // Doing something if the jwt invalid ?
            }
            else
            {
                return;
            }
            //... Some below process
        }
    }
    

    如果我的区块码想法是正确的,请看 string accessTokens = _userService.GetToken(_httpContextAccessor); ,注销,因为可能会有 null 在这里,由于你通过了 IHttpContextAccessor ,这是单身汉,不是单身汉 HttpContext 每个请求的作用域(localhost就可以了,因为我们只有一个客户机)。

    推荐文章