趁着武汉疫情,在家研究原来2.2的框架升级到3.1的问题,在过程中遇到不少坑,好在放假有的是时间,一个一个解决,现做个简要记录,供大家参考。
推荐认真看这篇文章
[https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio](https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio)
**其中,主要问题都是原来的包的版本依赖问题!花了很多时间去解决各个引用的包依赖的问题**
1.常见的其他网站都有提,比如:
移除包Microsoft.AspNetCore.App,已经不需要了
2.IHostingEnvironment变成了IWebHostEnvironment
3. 在Microsoft.AspNetCore.Http.HttpRequest.EnableRewind()这个方法,升级为Request.EnableBuffering ()
4.如果出现:
System.TypeLoadException:“Could not load type 'Microsoft.AspNetCore.Mvc.MvcJsonOptions' from assembly 'Microsoft.AspNetCore.Mvc.Formatters.Json, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.”
最后升级swagger版本g到最新的5.0得到解决,但是升级swagger,又发现:
IDocumentFilter 更改了接口,
命名空间也修改了:升级为using Microsoft.OpenApi.Models;
将tag=>OpenApiTag
原来的接口方法修改为:
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
swagger示例:
```
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "API接口文档",
Version = "v1",
Description = "API v1",
Contact = new OpenApiContact { Name = "wadereye", Email = "wader129-qq.com" }
});
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "......",
Name = "Authorization",
//这两个参数均有修改
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
...
});
```
5.如果出现:
System.MissingMethodException:“Method not found: 'Autofac.Builder.DeferredCallback Autofac.ContainerBuilder.RegisterCallback(System.Action`1
是autofac的版本问题,autofac我一开始更新到5.0,到处报错,后来查看5.0的文档,发现更新较多,于是又将相关的autofac 5.0包降到最新的4.9.4,很多问题得以解决。
6.如果你以前用过context.Resource as AuthorizationFilterContext这样的,在asp.net core 3.0已经不支持了。这个坑了我半天才找到解决方案。
在issue里找到这篇文章:
[https://github.com/aspnet/AspNetCore.Docs/issues/12564](https://github.com/aspnet/AspNetCore.Docs/issues/12564)
才发现其实在官方2.2升3.1的文章有介绍,只是一开始没看,原文这样介绍的:
#### Custom authorization handlers[](https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#custom-authorization-handlers)
If the app uses custom [authorization handlers](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1#authorization-handlers), endpoint routing passes a different resource type to handlers than MVC. Handlers that expect the authorization handler context resource to be of type [AuthorizationFilterContext](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters.authorizationfiltercontext) (the resource type [provided by MVC filters](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1#accessing-mvc-request-context-in-handlers)) will need to be updated to handle resources of type [RouteEndpoint](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.routing.routeendpoint) (the resource type given to authorization handlers by endpoint routing).
MVC still uses `AuthorizationFilterContext` resources, so if the app uses MVC authorization filters along with endpoint routing authorization, it may be necessary to handle both types of resources.
google翻译如下:
自定义授权处理程序 如果应用使用自定义授权处理程序,则端点路由会将与MVC不同的资源类型传递给处理程序。期望授权处理程序上下文资源的类型为AuthorizationFilterContext(由MVC过滤器提供的资源类型)的处理程序将需要更新,以处理RouteEndpoint类型的资源(端点路由提供给授权处理程序的资源类型)。
MVC仍使用AuthorizationFilterContext资源,因此,如果应用程序使用MVC授权过滤器以及端点路由授权,则可能有必要处理两种类型的资源。
所以获取的方式变了,很多需要通过endpoint的方式去获取。
具体的可以通过这篇文章来了解详细:
[https://damienbod.com/2019/12/02/using-http-request-routes-request-body-and-query-string-parameters-for-authorization-in-asp-net-core/](https://damienbod.com/2019/12/02/using-http-request-routes-request-body-and-query-string-parameters-for-authorization-in-asp-net-core/)
示例代码 可以看:
[https://github.com/damienbod/AspNetCoreWindowsAuth](https://github.com/damienbod/AspNetCoreWindowsAuth)
简要点说:作者建议这样玩:
(1)在ASP.NET核心中使用HTTP请求路由,请求主体和查询字符串参数进行授权
使用ASP.NET Core Route参数进行授权
An AuthorizationHandler can be used to implement authorization logic in ASP.NET Core. The handler can authorize HTTP requests using a route parameter from where the policy for the requirement used in the handler is defined. The IHttpContextAccessor is used to access the route parameters. The RouteValues property in the request of the HttpContext contains these values. If you know the name of the route value, the value can be retrieved using this key. In this demo, a static text is used to validate the route parameter value. In a real world AuthorizationHandler, the value would be validated against a claim from the token, or queried from a database, or an authorization service. To validate this correctly, something must be used which cannot be manipulated. If using a claim from the access token, then the access token must be validated fully and correctly. The AuthorizationHandler implements the ValuesRouteRequirement which is used in the policy definition.
可以使用AuthorizationHandler在ASP.NET Core中实现授权逻辑。处理程序可以使用route参数授权HTTP请求,从中定义处理程序中使用的需求策略。 IHttpContextAccessor用于访问路由参数。 HttpContext请求中的RouteValues属性包含这些值。如果知道路由值的名称,则可以使用此键检索该值。在此演示中,使用静态文本来验证路由参数值。在现实世界中的AuthorizationHandler中,将根据令牌中的声明对值进行验证,或者根据数据库或授权服务对其进行查询。为了正确验证这一点,必须使用一些无法操纵的东西。如果使用访问令牌中的声明,则必须完全正确地验证访问令牌。 AuthorizationHandler实现在策略定义中使用的ValuesRouteRequirement。
```
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace AppAuthorizationService
{
public class ValuesCheckRouteParameterHandler : AuthorizationHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ValuesCheckRouteParameterHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValuesRouteRequirement requirement)
{
var routeValues = _httpContextAccessor.HttpContext.Request.RouteValues;
object user;
routeValues.TryGetValue("user", out user);
if ( user.ToString() == "phil")
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
```
In the Startup class using the ConfigureServices method, the IAuthorizationHandler services are registered and also the IHttpContextAccessor using the AddHttpContextAccessor method. The policies are defined for the authorization requirements. The demo is an API project example, which uses swagger so the AddControllers extension method is used, with AddNewtonsoftJson.
在使用ConfigureServices方法的Startup类中,将注册IAuthorizationHandler服务,并使用AddHttpContextAccessor方法来注册IHttpContextAccessor。为授权要求定义了策略。该演示是一个API项目示例,该示例使用了大张旗鼓,因此将AddControllers扩展方法与AddNewtonsoftJson一起使用。
```
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddHttpContextAccessor();
services.AddSingleton
services.AddSingleton
services.AddSingleton
services.AddAuthorization(options =>
{
options.AddPolicy("protectedScope", policy =>
{
policy.RequireClaim("scope", "native_api");
});
options.AddPolicy("ValuesRoutePolicy", valuesRoutePolicy =>
{
valuesRoutePolicy.Requirements.Add(new ValuesRouteRequirement());
});
options.AddPolicy("ValuesQueryPolicy", valuesQueryPolicy =>
{
valuesQueryPolicy.Requirements.Add(new ValuesCheckQueryParamRequirement());
});
options.AddPolicy("ValuesRequestBodyCheckPolicy", valuesRequestBodyCheckPolicy =>
{
valuesRequestBodyCheckPolicy.Requirements.Add(new ValuesRequestBodyRequirement());
});
});
services.AddControllers()
.AddNewtonsoftJson();
}
```
The policy is then used in the controller in the authorize attribute. In this demo, if the user has the value ‘phil’, the data will be returned, otherwise a 403 is returned, or 401 if no bearer access token is sent in the header of the HTTP request.
然后在控制器的authorize属性中使用该策略。在此演示中,如果用户的值为“ phil”,则将返回数据,否则返回403,或者如果在HTTP请求的标头中未发送任何承载访问令牌,则返回401。
```
[Authorize("ValuesRoutePolicy")]
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet]
[Route("{user}", Name = nameof(GetWithRouteParam))]
public IActionResult GetWithRouteParam([FromRoute]string user)
{
return Ok($"get this data [{user}] using the route");
}
```
A HttpClient implementation can then make a HTTP request with the route set and the access token added to the headers.
然后,HttpClient实现可以发出带有路由集并将访问令牌添加到标头的HTTP请求
'''
private static async Task CallApiwithRouteValue(string currentAccessToken, string user)
{
_apiClient.SetBearerToken(currentAccessToken);
var response = await _apiClient.GetAsync($"/api/values/{user}");
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"\n{result}");
}
else
{
Console.WriteLine($"Error: {response.ReasonPhrase}");
}
}
'''
后面还有更详细的基于querystring的方法,我就不写了,看一下就明白 了。
另外推荐这几篇文章也看下:
[https://damienbod.com/2018/04/19/asp-net-core-authorization-for-windows-local-accounts/](https://damienbod.com/2018/04/19/asp-net-core-authorization-for-windows-local-accounts/)
[https://damienbod.com/2018/04/15/supporting-both-local-and-windows-authentication-in-asp-net-core-mvc-using-identityserver4/](https://damienbod.com/2018/04/15/supporting-both-local-and-windows-authentication-in-asp-net-core-mvc-using-identityserver4/)