带有身份的ASP.NET Core 5 - 可以用[授权]装饰的访问视图

发布于 2025-02-08 09:08:19 字数 6807 浏览 2 评论 0原文

我花了几个小时试图弄清楚为什么登录成功后无法访问视图。从Chrome工具中,我可以看到200个响应,即产生令牌。然后,如果成功的话,它应该导航到主页,但随后我得到了401(未经授权)。如果我删除[授权]装饰器或添加[washerAnymous]它有效,但这不是我想要的。从Swagger中,我看到了相同的行为。即使在401错误之后,令牌仍然存在。请帮忙!

appsettings.json (Hidding Key and Insuer)

  "JWTSettings": {
    "securityKey": "*********",
    "validIssuer": "*********",
    "validAudience": "https://localhost:44393",
    "expiryInMinutes": 5
  }

startup.cs

    services.AddDbContext<JonathanKrownContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JonathanKrownArtDb")));

    services.AddIdentity<User, IdentityRole>(opt =>
    {
        opt.User.RequireUniqueEmail = true;
    }).AddEntityFrameworkStores<JonathanKrownContext>();

    var jwtSettings = Configuration.GetSection("JWTSettings");
    services.AddAuthentication(opt =>
    {
        opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSettings["validIssuer"],
            ValidAudience = jwtSettings["validAudience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
                .GetBytes(jwtSettings.GetSection("securityKey").Value))
        };
    });

    services.AddScoped<JwtHandler>();

public class JwtHandler
{
    private readonly IConfiguration configuration;
    private readonly IConfigurationSection jwtSettings;
    public JwtHandler(IConfiguration configuration)
    {
        this.configuration = configuration;
        jwtSettings = this.configuration.GetSection("JwtSettings");
    }
    public SigningCredentials GetSigningCredentials()
    {
        var key = Encoding.UTF8.GetBytes(jwtSettings.GetSection("securityKey").Value);
        var secret = new SymmetricSecurityKey(key);
        return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
    }
    public List<Claim> GetClaims(IdentityUser user)
    {
        var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, user.Email)
    };
        return claims;
    }
    public JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
    {
        var tokenOptions = new JwtSecurityToken(
            issuer: jwtSettings["validIssuer"],
            audience: jwtSettings["validAudience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expiryInMinutes"])),
            signingCredentials: signingCredentials);
        return tokenOptions;
    }
}

   [Route("[controller]")]
    [ApiController]
    public class AccountsController : Controller
    {
        private readonly UserManager<DataModels.User> userManager;
        private readonly IMapper mapper;
        private readonly JwtHandler jwtHandler;

        public AccountsController(UserManager<DataModels.User> userManager, IMapper mapper, JwtHandler jwtHandler)
        {
            this.userManager = userManager;
            this.mapper = mapper;
            this.jwtHandler = jwtHandler;
        }
        [HttpPost("Registration")]
        public async Task<IActionResult> RegisterUser([FromBody] DomainModels.User userForRegistration)
        {
            if(userForRegistration == null || !ModelState.IsValid)
            {
                return BadRequest();
            }

            var user = mapper.Map<DataModels.User>(userForRegistration);

            var result = await userManager.CreateAsync(user, userForRegistration.Password);
            if(!result.Succeeded)
            {
                var errors = result.Errors.Select(e => e.Description);

                return BadRequest(new DomainModels.RegistrationResponse { Errors = errors });
            }

            return StatusCode(201);
        }

        [HttpPost("Login")]
        public async Task<IActionResult> Login([FromBody] UserForAuthentication userForAuthentication)
        {
            var user = await userManager.FindByNameAsync(userForAuthentication.Email);

            if(user == null || !await userManager.CheckPasswordAsync(user, userForAuthentication.Password))
            {
                return Unauthorized(new AuthResponse { ErrorMessage = "Invalid Authentication" });
            }

            var signinCredentials = jwtHandler.GetSigningCredentials();
            var claims = jwtHandler.GetClaims(user);
            var tokenOptions = jwtHandler.GenerateTokenOptions(signinCredentials, claims);
            var token = new JwtSecurityTokenHandler().WriteToken(tokenOptions);

            return Ok(new AuthResponse { IsAuthSuccessful = true, Token = token });
        }
    }

[Route("[controller]")]
    [Authorize]
    [ApiController]
    public class PaintingsController : Controller
    {
        private readonly IPaintingRepository repository;
        private readonly IMapper mapper;
        private readonly ILogger<PaintingsController> logger;
        private readonly IImageRepository imageRepository;

        public PaintingsController(IPaintingRepository repository, IMapper mapper, ILogger<PaintingsController> logger, IImageRepository imageRepository)
        {
            this.repository = repository;
            this.mapper = mapper;
            this.logger = logger;
            this.imageRepository = imageRepository;
        }

        [HttpGet]
        [ProducesResponseType(200)]
        [ProducesResponseType(400)]
        public async Task<IActionResult> GetAllPaintingsAsync()
        {
            try
            {
                var claims = User.Claims;
                var paintings = await repository.GetHomePagePaintingsAsync();
                var paintingsDto = mapper.Map<List<Painting>>(paintings);

                return Ok(paintingsDto);
            }
            catch (Exception ex)
            {
                logger.LogError($"Failed to get paintings: {ex}");
                return BadRequest("Failed to get paintings");
            }
        }
}

​“ alt =”令牌仍然存在,即使在401错误之后”>

“

I’ve spent hours trying to figure out why I can’t access a view after login is successful. From the Chrome tools I can see a 200 response, token being generated. Then it should navigate to the home page if successful, which it tries, but then I get a 401 (Unauthorized). If I remove the [Authorize] decorator or add an [AllowAnonymous] it works but that is not what I am looking for. From swagger I see the same behavior. Token persists even after the 401 error. Please help!

appsettings.json (hidding key and issuer)

  "JWTSettings": {
    "securityKey": "*********",
    "validIssuer": "*********",
    "validAudience": "https://localhost:44393",
    "expiryInMinutes": 5
  }

Startup.cs

    services.AddDbContext<JonathanKrownContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JonathanKrownArtDb")));

    services.AddIdentity<User, IdentityRole>(opt =>
    {
        opt.User.RequireUniqueEmail = true;
    }).AddEntityFrameworkStores<JonathanKrownContext>();

    var jwtSettings = Configuration.GetSection("JWTSettings");
    services.AddAuthentication(opt =>
    {
        opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSettings["validIssuer"],
            ValidAudience = jwtSettings["validAudience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
                .GetBytes(jwtSettings.GetSection("securityKey").Value))
        };
    });

    services.AddScoped<JwtHandler>();

JwtHandler.cs

public class JwtHandler
{
    private readonly IConfiguration configuration;
    private readonly IConfigurationSection jwtSettings;
    public JwtHandler(IConfiguration configuration)
    {
        this.configuration = configuration;
        jwtSettings = this.configuration.GetSection("JwtSettings");
    }
    public SigningCredentials GetSigningCredentials()
    {
        var key = Encoding.UTF8.GetBytes(jwtSettings.GetSection("securityKey").Value);
        var secret = new SymmetricSecurityKey(key);
        return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
    }
    public List<Claim> GetClaims(IdentityUser user)
    {
        var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, user.Email)
    };
        return claims;
    }
    public JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
    {
        var tokenOptions = new JwtSecurityToken(
            issuer: jwtSettings["validIssuer"],
            audience: jwtSettings["validAudience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["expiryInMinutes"])),
            signingCredentials: signingCredentials);
        return tokenOptions;
    }
}

AccountsController.cs

   [Route("[controller]")]
    [ApiController]
    public class AccountsController : Controller
    {
        private readonly UserManager<DataModels.User> userManager;
        private readonly IMapper mapper;
        private readonly JwtHandler jwtHandler;

        public AccountsController(UserManager<DataModels.User> userManager, IMapper mapper, JwtHandler jwtHandler)
        {
            this.userManager = userManager;
            this.mapper = mapper;
            this.jwtHandler = jwtHandler;
        }
        [HttpPost("Registration")]
        public async Task<IActionResult> RegisterUser([FromBody] DomainModels.User userForRegistration)
        {
            if(userForRegistration == null || !ModelState.IsValid)
            {
                return BadRequest();
            }

            var user = mapper.Map<DataModels.User>(userForRegistration);

            var result = await userManager.CreateAsync(user, userForRegistration.Password);
            if(!result.Succeeded)
            {
                var errors = result.Errors.Select(e => e.Description);

                return BadRequest(new DomainModels.RegistrationResponse { Errors = errors });
            }

            return StatusCode(201);
        }

        [HttpPost("Login")]
        public async Task<IActionResult> Login([FromBody] UserForAuthentication userForAuthentication)
        {
            var user = await userManager.FindByNameAsync(userForAuthentication.Email);

            if(user == null || !await userManager.CheckPasswordAsync(user, userForAuthentication.Password))
            {
                return Unauthorized(new AuthResponse { ErrorMessage = "Invalid Authentication" });
            }

            var signinCredentials = jwtHandler.GetSigningCredentials();
            var claims = jwtHandler.GetClaims(user);
            var tokenOptions = jwtHandler.GenerateTokenOptions(signinCredentials, claims);
            var token = new JwtSecurityTokenHandler().WriteToken(tokenOptions);

            return Ok(new AuthResponse { IsAuthSuccessful = true, Token = token });
        }
    }

PaintingsController.cs

[Route("[controller]")]
    [Authorize]
    [ApiController]
    public class PaintingsController : Controller
    {
        private readonly IPaintingRepository repository;
        private readonly IMapper mapper;
        private readonly ILogger<PaintingsController> logger;
        private readonly IImageRepository imageRepository;

        public PaintingsController(IPaintingRepository repository, IMapper mapper, ILogger<PaintingsController> logger, IImageRepository imageRepository)
        {
            this.repository = repository;
            this.mapper = mapper;
            this.logger = logger;
            this.imageRepository = imageRepository;
        }

        [HttpGet]
        [ProducesResponseType(200)]
        [ProducesResponseType(400)]
        public async Task<IActionResult> GetAllPaintingsAsync()
        {
            try
            {
                var claims = User.Claims;
                var paintings = await repository.GetHomePagePaintingsAsync();
                var paintingsDto = mapper.Map<List<Painting>>(paintings);

                return Ok(paintingsDto);
            }
            catch (Exception ex)
            {
                logger.LogError(
quot;Failed to get paintings: {ex}");
                return BadRequest("Failed to get paintings");
            }
        }
}

Token persists even after the 401 error

401 error

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文