我是一名后端开发人员,他通常在同一个项目下开发API和管理面板。我主要使用Laravel / PHP,但是我最近开始深入研究.NET Core。
在PHP(Laravel)中,我可以将我的API端点和网页绑定到相同的控制器操作。例如,API使用者应该能够使用API端点创建博客文章。此外,管理员应该能够使用Web UI创建博客文章,该博客应遵循相同的验证逻辑等。
以下是create
操作的一些伪代码。
class BlogPostController
{
//Create a new blog post
function create(request)
{
authorizeAction(); //Make sure the current user is authorized to create a blog post
validateFields(request); //Make sure the posted data is valid for a blog post
//Create the blog post
blogPost = new BlogPost(request);
if(request.isAPI)
return json(blogPost); //Return the new blog post as a json string
return view(blogPost); //Return an HTML representation of the blog post (in administration panel)
}
}
在Laravel中,由于所有路由都可以有不同的中间件,我可以定义两条上述操作的路由,例如POST
/api/blogpost
和POST
/blogpost
,每条路由都有不同的身份验证方案。 (api将通过JWT令牌进行授权,并且网址将通过cookie进行授权)。
我无法在.NET Core中执行类似操作,因为不同的身份验证方案无法通过单独的中间件as of Version 2应用(据我所知)。
我对此问题的解决方案是添加两种身份验证方案,如下所示:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg=>cfg.SlidingExpiration = true)
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero
};
});
然后在我的控制器上使用:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme + "," + CookieAuthenticationDefaults.AuthenticationScheme)]
这将有效地挑战JWT令牌和cookie,并使用它找到的任何一个。这对我来说似乎有些混乱(和Microsoft employee would agree)
我是否接近整个问题?对我来说,将所有逻辑保留在一个控制器中并根据请求的类型返回json或HTML是有意义的。我可以为API端点和网页设置一个单独的控制器,但它似乎有很多重复的代码。另一种选择是彻底抛弃这个想法,只需构建一个消耗API的API /单页应用程序。
这是一个简单的糟糕设计,还是根据路线使用不同的身份验证方案?