我有一个带有MVC的Web API应用程序.当用户使用该网站时,身份验证和授权当前由我使用的全局表单身份验证自动处理,在Web.config中配置如下:
<authentication mode="Forms">
<forms loginUrl="~/Login" slidingExpiration="true" timeout="1800" defaultUrl="/"></forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
这样可确保只有登录的用户才能访问该站点并调用API.
但我也有一个外部Windows客户端,我想使用另一种身份验证方法.在没有表单身份验证的测试中,我设置了一个自定义AuthorizeAttribute,我可以在我的控制器中使用,如下所示:
[ApiAuth]
public IEnumerable<string> Get() {
// Return the resource
}
AuthorizeAttribute看起来像这样:
public class ApiAuthAttribute : AuthorizeAttribute {
public override void OnAuthorization(HttpActionContext context) {
// Authenticate the request with a HMAC-based approach
}
}
这在隔离工作正常,但我无法弄清楚如何允许两种auth方法.我希望ApiAuth作为后备,如果表单auth不起作用(或反过来,无论什么工作),但如果我应用[ApiAuth]属性,只会使用它,普通用户无法访问api.
那么,我如何使用多个auth方法,或者使用其中一个作为后备,如果另一个失败,或者配置服务器,以便Windows客户端可以以其他方式调用API,然后保持相同的MVC应用程序API调用可用于两种类型的客户端?
谢谢.
编辑:我可能采取的一种方法是让Windows客户端使用表单身份验证(类似于this)进行身份验证,但它看起来非常像黑客,我宁愿使用其他方法.
最佳答案 FormAuthentication可以实现多种方式.在过去,我们使用
FormAuthentication Ticket.
现在,您可以使用基于声明的身份验证与Owin Middleware,它基本上是ASP.Net Identity的精简版本.
在ApiAuthAttribute中对用户进行身份验证后,您将创建Principal对象.
Web.config文件
你不应该使用< authorization> ASP.Net MVC中的标记.相反,您想要使用过滤器.
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
ApiAuthAttribute
public class ApiAuthAttribute : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext context)
{
// Authenticate the request with a HMAC-based approach
// Create FormAuthentication after custom authentication is successful
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
User user = new User {Id = "1234", UserName = "johndoe",
FirstName = "John", LastName = "Doe"};
// This should be injected using IoC container.
var service = new OwinAuthenticationService(
new HttpContextWrapper(HttpContext.Current));
service.SignIn(user);
}
}
}
认证
public class User
{
public string Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IAuthenticationService
{
void SignIn(User user);
void SignOut();
}
public class OwinAuthenticationService : IAuthenticationService
{
private readonly HttpContextBase _context;
private const string AuthenticationType = "ApplicationCookie";
public OwinAuthenticationService(HttpContextBase context)
{
_context = context;
}
public void SignIn(User user)
{
IList<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Sid, user.Id),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
};
/*foreach (Role role in user.Roles)
{
claims.Add(new Claim(ClaimTypes.Role, role.Name));
}*/
ClaimsIdentity identity = new ClaimsIdentity(claims, AuthenticationType);
IOwinContext context = _context.Request.GetOwinContext();
IAuthenticationManager authenticationManager = context.Authentication;
authenticationManager.SignIn(identity);
}
public void SignOut()
{
IOwinContext context = _context.Request.GetOwinContext();
IAuthenticationManager authenticationManager = context.Authentication;
authenticationManager.SignOut(AuthenticationType);
}
}
Startup.cs
[assembly: OwinStartup(typeof(YOUR_APPLICATION.Startup))]
namespace YOUR_APPLICATION
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/Account/Login")
});
}
}
}