asp.net-core - 在重定向到其他 URL 并且没有身份验证的情况下在 cookie 上存储声明
问题描述
我只需要建议这是否可行。我正在为我的 Shopify 应用程序开发授权,并且我需要存储来自 shopify auth 的访问令牌,以便将来验证我的前端应用程序。
所以 shopify 调用的第一个端点是这个:
[HttpGet("install")]
public async Task<IActionResult> Install()
{
try
{
if (ModelState.IsValid)
{
var queryString = Request.QueryString.Value;
var isValid = _shopifyService.VerifyRequest(queryString);
if (isValid)
{
var shopifyUrl = Request.Query["shop"];
var authUrl = _shopifyService.BuildAuthUrl(shopifyUrl,
$"{Request.Scheme}://{Request.Host.Value}/api/shopify/authorize",
Program.Settings.Shopify.AuthorizationScope);
return Redirect(authUrl);
}
}
}
catch (Exception ex)
{
var exceptionMessage = await ApiHelpers.GetErrors(ex, _localizer).ConfigureAwait(false);
ModelState.AddModelError(new ValidationResult(exceptionMessage));
}
ModelState.AddModelError(new ValidationResult(_localizer["InvalidAuthStore"]));
return BadRequest(ModelState.GetErrors());
}
这工作正常,这个 api 调用的结果实际上将重定向到我的 api 的相同链接,但是这个将授权应用程序:
[HttpGet("authorize")]
public async Task<IActionResult> AuthorizeStore()
{
try
{
if (ModelState.IsValid)
{
var code = Request.Query["code"];
var shopifyUrl = Request.Query["shop"];
var accessToken = await _shopifyService.AuthorizeStore(code, shopifyUrl).ConfigureAwait(false);
var identity = User.Identity as ClaimsIdentity;
identity.AddClaim(new Claim(Constants.Claims.AccessToken, accessToken));
// genereate the new ClaimsPrincipal
var claimsPrincipal = new ClaimsPrincipal(identity);
// store the original tokens in the AuthenticationProperties
var props = new AuthenticationProperties {
AllowRefresh = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1),
IsPersistent = false,
IssuedUtc = DateTimeOffset.UtcNow,
};
// sign in using the built-in Authentication Manager and ClaimsPrincipal
// this will create a cookie as defined in CookieAuthentication middleware
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, props).ConfigureAwait(false);
Uri uri = new Uri($"{Program.Settings.Shopify.RedirectUrl}?token={accessToken}");
return Redirect(uri.ToString());
}
}
catch (Exception ex)
{
var exceptionMessage = await ApiHelpers.GetErrors(ex, _localizer).ConfigureAwait(false);
ModelState.AddModelError(new ValidationResult(exceptionMessage));
}
ModelState.AddModelError(new ValidationResult(_localizer["InvalidAuthStore"]));
return BadRequest(ModelState.GetErrors());
}
所以上面的 api 将在 shopify 中授权我的应用程序并返回一个访问令牌。accessToken 是我要保存在具有 Cookie 身份验证类型的声明身份中的那个(这没有授权用户凭据)。此时仍然没有错误,在调用HttpContext.SignInAsync
函数后,我仍然可以使用调试器查看新添加的声明。
如您在代码中所见,在分配声明后,我调用以将应用程序重定向到前端链接(注意:前端和后端具有不同的 url)
在我的前端应用程序中,我有一个 Nuxt 中间件,我放置了一个逻辑来检查从后端接收到的令牌,因为我只使用查询参数将令牌传递给前端应用程序。这是我的中间件代码:
export default function ({ app, route, next, store, error, req }) {
if (process.browser) {
const shopifyAccessToken = store.get('cache/shopifyAccessToken', null)
if (!shopifyAccessToken && route.query.token) {
// if has token on query params but not yet in cache, store token and redirect
store.set('cache/shopifyAccessToken', route.query.token)
app.router.push({
path: '/',
query: {}
})
// verify access token on the route
app.$axios
.get(`/shopify/verifyaccess/${route.query.token}`)
.catch((err) => {
error(err)
})
} else if (!shopifyAccessToken && !route.query.token) {
// if does not have both, throw error
error({
statusCode: 401,
message: 'Unauthorized access to this app'
})
}
} else {
next()
}
}
在我的中间件中,当路由的查询参数等于时,token=
它会调用另一个 api 来验证保存在我的声明身份中的 accessToken:
[HttpGet("verifyaccess/{accessToken}")]
public async Task<IActionResult> VerifyAccess(string accessToken)
{
try
{
if (ModelState.IsValid)
{
var principal = HttpContext.User;
if (principal?.Claims == null)
return Unauthorized(_localizer["NotAuthenticated"]);
var accessTokenClaim = principal.FindFirstValue(Constants.Claims.AccessToken);
if (accessToken == accessTokenClaim)
{
return Ok();
}
else
{
return Unauthorized(_localizer["NotAuthenticated"]);
}
}
}
catch (Exception ex)
{
var exceptionMessage = await ApiHelpers.GetErrors(ex, _localizer).ConfigureAwait(false);
ModelState.AddModelError(new ValidationResult(exceptionMessage));
}
ModelState.AddModelError(new ValidationResult(_localizer["InvalidAuthStore"]));
return BadRequest(ModelState.GetErrors());
}
查看上面的代码,它总是让我失败,因为我保存在authorize
端点上的声明身份不存在,或者简而言之,ClaimsIdentity 总是空的。
以下是我注册 Cookie 配置的方法:
private void ConfigureAuthCookie(IServiceCollection services)
{
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.RequireAuthenticatedSignIn = false;
})
.AddCookie(options => {
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.SlidingExpiration = true;
options.Cookie.Name = "shopifytoken";
});
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.None;
});
}
我还在我的 Startup.Configure 上放了一个app.UseAuthentication()
andapp.UseAuthorization()
如果这看起来令人困惑,请告诉我,以便我进行修改。我的主要目标是能够访问我保存在 ClaimsIdentity 中的 accessToken,以便验证令牌。我这样做的原因是因为目前 shopify 没有用于验证访问令牌的 API。因此,当用户像这样访问我的应用程序链接时,http://example.com/?token=<any incorrect token>
他们已经可以访问我的应用程序。
解决方案
推荐阅读
- wordpress - Wordpress 管理员管理员更改按钮文本添加新
- html - CSS 图像和伪元素过渡不同步
- r - 如何修复 bsts 包 R 中的“.ValidateHolidayList(holiday.list) 中的错误”?
- apache-kafka-streams - Kafka Streams:使用 at_least_once 时,为状态存储更改日志主题提供了哪些排序保证?
- sql - 使用 Vertica 插入 SQL 表时出现资源不足错误
- typescript - Typescript - 将接口属性转换为通用
- c# - 如何一起创建平移和倾斜控件?
- office-js - Office 加载项要求
- javascript - XMLHttpRequest onload() 函数未传递 XMLHttpRequest 对象
- javascript - 如何将对象发送到类参数javascript?