.Net Framework 4.6.1 WebApi,属性路由和默认路由不起作用

Posted

技术标签:

【中文标题】.Net Framework 4.6.1 WebApi,属性路由和默认路由不起作用【英文标题】:.Net Framework 4.6.1 WebApi, Attribute routing and default routing not working 【发布时间】:2021-06-10 22:39:24 【问题描述】:

感谢您对此提供的任何帮助。我目前正在从事一个项目,我们基本上必须将较旧的 .Net Framework MVC 应用程序转换为 React 前端使用的 API。我们基本上能够在不使用 ApiController 的情况下将 MVC 控制器转换为 API 控制器。现在我们意识到我们需要保护 API,并决定实施 JWT。

我能够实现 JWT 令牌创建,并且我在我的帐户控制器中工作,它正在返回 JWT。我遇到的问题是我想在某些端点上实现授权,但在现有控制器上工作时遇到了问题。 https://github.com/DavidParks8/Owin-Authorization/wiki/Claims-Based-Authorization 的文档说明我应该能够在任一类型的控制器上使用授权,所以我不知道我做错了什么。

我想可能是因为我使用的是 Controller 而不是 ApiController,所以我设置了一个测试控制器,并根据我遵循的 JWT 教程创建了一些基本端点。问题是,当我尝试测试这些端点时,它们根本没有被击中,而我得到的是 404。

这是我的配置:

        
            string secretKey = WebConfigurationManager.AppSettings["SecretKey"];
            SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

            // Configure the db context, user manager and signin manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);


            //Enable JWT Authentication:

            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                
                    AuthenticationMode = AuthenticationMode.Active,
                    TokenValidationParameters = new TokenValidationParameters()
                    
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = WebConfigurationManager.AppSettings["Audience"],  
                        ValidAudience = WebConfigurationManager.AppSettings["Audience"],
                        IssuerSigningKey = _signingKey,
                        ClockSkew = TimeSpan.Zero,
                        ValidateLifetime = true,
                        RequireExpirationTime = false
                    ,
                    
                );
            //AuthorizationOptions options = new AuthorizationOptions();
            app.UseAuthorization(options =>
            
                options.AddPolicy("Principal", policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, "Principal"));
                options.AddPolicy("Employee", policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.Employee));
                options.AddPolicy("Warranty", policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.Principal));
                options.AddPolicy("Admin", policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.Principal));
            );

这是基于我阅读的文档和教程,并使用 Microsoft.Owin.Security.Authorization 和 Microsoft.Owin.Security.Jwt

这是我的 WebApiConfig:

public static class WebApiConfig
    
        public static void Register(HttpConfiguration config)
        
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
            var json = config.Formatters.JsonFormatter;
            json.SupportedMediaTypes
                .Add(new MediaTypeHeaderValue("text/html"));
            json.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.EnableCors();

            //config.MessageHandlers.Add(new TokenValidationHandler());

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/controller/action/id",
                defaults: new  id = RouteParameter.Optional 
            );

            //var jsonpFormatter = new JsonpMediaTypeFormatter(config.Formatters.JsonFormatter);
            //config.Formatters.Insert(0, jsonpFormatter);
        
    

这是我的测试控制器:

public class TestController : ApiController
    
        [HttpGet]
        [AllowAnonymous]
        [Route("GetToken")]
        public Object GetToken()
        
            string key = "my_secret_key_12345"; //Secret key which will be used later during validation    
            var issuer = "example.com";  //normally this will be your site URL    

            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            //Create a List of Claims, Keep claims name short    
            var permClaims = new List<Claim>();
            permClaims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
            permClaims.Add(new Claim("valid", "1"));
            permClaims.Add(new Claim("userid", "1"));
            permClaims.Add(new Claim("name", "bilal"));

            //Create Security Token object by giving required parameters    
            var token = new JwtSecurityToken(issuer, //Issuer    
                issuer,  //Audience    
                permClaims,
                expires: DateTime.Now.AddDays(1),
                signingCredentials: credentials);
            var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
            return new  data = jwtToken ;
        

        [HttpGet]
        [AllowAnonymous]
        [Route("GetName1")]
        public string GetName1()
        
            if (User.Identity.IsAuthenticated)
            
                var identity = User.Identity as ClaimsIdentity;
                if (identity != null)
                
                    IEnumerable<Claim> claims = identity.Claims;
                
                return "Valid";
            
            else
            
                return "Invalid";
            
        


        [HttpPost]
        [Route("GetName2")]
        public Object GetName2()
        
            if (User.Identity is ClaimsIdentity identity)
            
                IEnumerable<Claim> claims = identity.Claims;
                var name = claims.Where(p => p.Type == "name").FirstOrDefault()?.Value;
                return new
                
                    data = name
                ;

            
            return null;
        
    

所以当我尝试调用 http://localhost:29523/api/Test/GetToken 时,我收到了 404 错误。我正在使用 Postman,我可以在另一个控制器中访问端点,但它是一个 MVC 控制器,它不遵循 API 路由。例如,/registration/GetAccountManagementInfo?userGuid=a182235e-c71d-47a5-b31d-f556288b3c3f 有效,我能够得到响应。

总而言之,我使用此 ApiController 进行测试的原因是,如果我可以完成这项工作,并获得授权以在 ApiController 上工作,那么我将把我的“注册”控制器转换为 ApiController,因为我让该控制器使用我设置的授权中间件时遇到问题。

无论如何,我确信我可以提供其他信息,但此时我正在努力找出如何进一步解决此问题。

我知道它正在尝试到达控制器,因为如果我添加一个构造函数,它会在构造函数处遇到断点,但无法从那里找到路由。我看不出我的设置有什么问题,但我觉得这个设置必须在某个地方交叉一些电线。这是我继承的应用程序。我希望我可以使用 .Net 核心开始一个新项目,但我们现在没有时间。

无论如何,对于这篇文章的长度感到抱歉,我真的希望有人能给我一些指导。到目前为止,我已经浏览了无数其他帖子,但到目前为止我还没有找到任何可以帮助我解决这个问题的帖子。

【问题讨论】:

为什么你把net 4和net core混在一起了?你真正使用的是什么? 您应该确保它是您实际尝试访问的 URI 上的纯 404。因为 Identity 存在一个众所周知的重定向问题,您看到的实际上是一个 302 重定向首先到一个不存在的地址(在某些情况下)。 它针对 .Net 4.6.1,app.UseAuthorization 来自一个 nuget 包,其中 Authorize 内容被反向移植到 .net 4 github.com/DavidParks8/Owin-Authorization 另外,您在非 api 控制器端点上的授权遇到的具体问题是什么?我想你没有提到这一点。 Leaky,这很有趣,如果您有任何相关链接,将不胜感激。我会根据你说的做一些搜索。 【参考方案1】:

你试过了吗?看来您不必在地址中输入Test。在您的情况下,它应该没有“测试”。

http://localhost:29523/api/GetToken

【讨论】:

以上是关于.Net Framework 4.6.1 WebApi,属性路由和默认路由不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Win10企业版安装NET Framework时出现"这台计算机中已经安装了.NET Framework 4.6.1或版本更高的更新"错误

netstandard2.0 (.net standard 2.0) 类库不能引用 net461 (.net framework 4.6.1) 类库

使用 .NET Core(.NET Standard 1.4 和 .NET Framework 4.6.1)对 System.Net.Http 使用 await/async 时出现错误?

.Net Framework 4.6.1 WebApi,属性路由和默认路由不起作用

在库中使用 .Net Standard 1.4 和在应用程序中使用 .Net framework 4.6.1 时,无法加载文件 System.IO.FileSystem,Version=4.0.1.0

我可以将 C# 7.3 与 .Net Framework 4.6.1 一起使用吗?