不记名身份验证来自邮递员,而不是来自 android 应用程序
Bearer authentication working from postman but not from android app
我遇到了一个奇怪的问题,它有点复杂,但我会尽力解释它。
我有一个 运行 在 ASP.Net Core 2.2 上运行的 CMS。我最近在 cookie 身份验证中添加了使用 JWT 的 Bearer 身份验证。 Startup.cs
文件如下所示:
services.AddAuthentication()
.AddCookie(cfg =>
{
cfg.SlidingExpiration = true;
cfg.ExpireTimeSpan = TimeSpan.FromMinutes(20);
cfg.LoginPath = new PathString("/account/login");
cfg.AccessDeniedPath = new PathString("/Account/AccessDenied");
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
[...]
services.ConfigureApplicationCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
options.SlidingExpiration = true;
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder() //makes every controller an every action requiring authorization except if labled by [AllowAnnonymous]
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
所以,如你所见,cookie认证是主要用途,我想在Bearer上使用的每个功能API,我注释如下:
[HttpGet]
[Produces("application/json")]
[Route("api/[controller]/[action]/")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public ActionResult GetUserDetails()
{
...
}
几个月来,这在不同的 .NET 应用程序中运行良好,当然还有邮递员。但是现在我想连接一个 Android 应用程序(使用 Java 和改造)和 none 的功能工作,即使我在HTTP 请求。一旦我删除了 Authorize
注释并将其替换为 AllowAnonymous
它就起作用了,奇怪的部分来了:我可以在请求中看到 Authorization
参数 header.
这里是一些截图:
从 Authorization
活动的 Postman 调用的函数 - 成功返回:
从 android 应用程序调用的函数 Authorization
处于活动状态。控制器操作甚至没有被击中,而是请求被重定向到 CMS 的登录页面(顺便说一句,同样的事情发生了,当我从邮递员那里拿令牌到 android 应用程序和 运行请求与我用于邮递员的令牌完全相同):
现在,当我删除控制器上的 Authorize
属性并添加一个 AllowAnonymous
时,它就像一个魅力,但我可以看到即使 header 包含Authorization
属性,用户显示为未经身份验证:
我已经坚持了几个小时了,我试图改变 Startup.cs
文件中的一些东西,我阅读了大量关于改造、oAuth2、Bearer 等的文章,但不幸的是找不到到目前为止有任何帮助。
所以对我来说,这种行为看起来很奇怪,我的问题是,我是否在这里遗漏了一些东西,header 中除了 Authorization
之外的任何特殊信息或其他什么?
任何输入将不胜感激。
编辑 1:
这是 Java (Android) 应用程序的代码:
//Endpoint
public interface TradeEndPoint {
@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("Trade/getAllActiveItemsApi")
Call<List<TradeItem>> getAllActiveItems(@Header("Authorization") String authHeader);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl.getStringValue())
.addConverterFactory(GsonConverterFactory.create())
.build();
TradeEndPoint te = retrofit.create(TradeEndPoint.class);
final Call<List<TradeItem>> getItems = te.getAllActiveItems("Bearer " + getAccessToken(context));
getItems.enqueue(new Callback<List<TradeItem>>() {
@Override
public void onResponse(Call<List<TradeItem>> call, Response<List<TradeItem>> response) {
TradeItemsLoaded til = (TradeItemsLoaded) fragment;
til.onTradeItemsLoaded(response);
}
@Override
public void onFailure(Call<List<TradeItem>> call, Throwable t) {
t.printStackTrace();
}
});
函数 getAccessToken(context)
returns 将标记作为字符串。
这是提琴手的截图session。
这是来自 android 应用程序
这来自 Postman(或 Firefox 的等效扩展,称为 RESTer)
所以是的,在 header 中存在差异,但如果有的话,哪一个是重要的?
我找到了解决方案。
在 Startup.cs
文件中有以下表达式:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
事实证明,授权过滤器在使用 postman 和 .NET 时确实有效,但由于某种原因,当从 android 应用程序使用 Bearer 身份验证时会出现问题。
我删除了这个,现在看起来像这样:
services.AddMvc()
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
现在我需要用 [Authorize]
注释每个控制器,但至少它可以工作(也许你也可以让授权过滤器与 android 一起工作,但无论如何我都没有使用它,所以这没什么大不了的)。
我遇到了一个奇怪的问题,它有点复杂,但我会尽力解释它。
我有一个 运行 在 ASP.Net Core 2.2 上运行的 CMS。我最近在 cookie 身份验证中添加了使用 JWT 的 Bearer 身份验证。 Startup.cs
文件如下所示:
services.AddAuthentication()
.AddCookie(cfg =>
{
cfg.SlidingExpiration = true;
cfg.ExpireTimeSpan = TimeSpan.FromMinutes(20);
cfg.LoginPath = new PathString("/account/login");
cfg.AccessDeniedPath = new PathString("/Account/AccessDenied");
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
[...]
services.ConfigureApplicationCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
options.SlidingExpiration = true;
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder() //makes every controller an every action requiring authorization except if labled by [AllowAnnonymous]
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
所以,如你所见,cookie认证是主要用途,我想在Bearer上使用的每个功能API,我注释如下:
[HttpGet]
[Produces("application/json")]
[Route("api/[controller]/[action]/")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public ActionResult GetUserDetails()
{
...
}
几个月来,这在不同的 .NET 应用程序中运行良好,当然还有邮递员。但是现在我想连接一个 Android 应用程序(使用 Java 和改造)和 none 的功能工作,即使我在HTTP 请求。一旦我删除了 Authorize
注释并将其替换为 AllowAnonymous
它就起作用了,奇怪的部分来了:我可以在请求中看到 Authorization
参数 header.
这里是一些截图:
从 Authorization
活动的 Postman 调用的函数 - 成功返回:
从 android 应用程序调用的函数 Authorization
处于活动状态。控制器操作甚至没有被击中,而是请求被重定向到 CMS 的登录页面(顺便说一句,同样的事情发生了,当我从邮递员那里拿令牌到 android 应用程序和 运行请求与我用于邮递员的令牌完全相同):
现在,当我删除控制器上的 Authorize
属性并添加一个 AllowAnonymous
时,它就像一个魅力,但我可以看到即使 header 包含Authorization
属性,用户显示为未经身份验证:
我已经坚持了几个小时了,我试图改变 Startup.cs
文件中的一些东西,我阅读了大量关于改造、oAuth2、Bearer 等的文章,但不幸的是找不到到目前为止有任何帮助。
所以对我来说,这种行为看起来很奇怪,我的问题是,我是否在这里遗漏了一些东西,header 中除了 Authorization
之外的任何特殊信息或其他什么?
任何输入将不胜感激。
编辑 1:
这是 Java (Android) 应用程序的代码:
//Endpoint
public interface TradeEndPoint {
@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("Trade/getAllActiveItemsApi")
Call<List<TradeItem>> getAllActiveItems(@Header("Authorization") String authHeader);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl.getStringValue())
.addConverterFactory(GsonConverterFactory.create())
.build();
TradeEndPoint te = retrofit.create(TradeEndPoint.class);
final Call<List<TradeItem>> getItems = te.getAllActiveItems("Bearer " + getAccessToken(context));
getItems.enqueue(new Callback<List<TradeItem>>() {
@Override
public void onResponse(Call<List<TradeItem>> call, Response<List<TradeItem>> response) {
TradeItemsLoaded til = (TradeItemsLoaded) fragment;
til.onTradeItemsLoaded(response);
}
@Override
public void onFailure(Call<List<TradeItem>> call, Throwable t) {
t.printStackTrace();
}
});
函数 getAccessToken(context)
returns 将标记作为字符串。
这是提琴手的截图session。
所以是的,在 header 中存在差异,但如果有的话,哪一个是重要的?
我找到了解决方案。
在 Startup.cs
文件中有以下表达式:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
})
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
事实证明,授权过滤器在使用 postman 和 .NET 时确实有效,但由于某种原因,当从 android 应用程序使用 Bearer 身份验证时会出现问题。
我删除了这个,现在看起来像这样:
services.AddMvc()
.AddViewLocalization(
options => { options.ResourcesPath = "Resources"; })
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
现在我需要用 [Authorize]
注释每个控制器,但至少它可以工作(也许你也可以让授权过滤器与 android 一起工作,但无论如何我都没有使用它,所以这没什么大不了的)。