Reputation: 1072
Our web applications use external authentication, in a sense that users' usernames/passwords aren't validated locally, but are being validated "outside" the web app in a central, single-sign-on type website. The authentication proof (and user's identification) becomes available via local server variables (HTTP_EMPLOYEEID
, etc.). However, it's not quite external like authenticating against Google, Facebook, or another OAuth based setup. So I just wanted to make that distinction, so it doesn't collide with terms "External Logins" in ASP.NET Identity / Owin.
I'm trying to figure out a clean way to leverage the authenticated user data (from server variables) and pass it over to ASP.NET authentication. However, the user profile and role data has to be looked up against a web service before the user can be logged into the app.
I want to use Owin and Claims-based identity, but I am not sure if I should also use ASP.NET Identity, as well, or just do a more "pure" implementation with claims. I like the idea of not reinventing the wheel, but I also don't want to force a square peg into a round hole (as the saying goes), if the way the user is identified and looked up from a web service does not fit a typical ASP.NET Identity usage.
For example, if I take a more purist approach, I could do something like:
// Get the current user's id
var userId = HttpContext.Current.Request.ServerVariables["HTTP_EMPLOYEEID"];
// Get profile and role data from a web service
MyUser user = MyUserService.GetUserById(userId);
// Create claims
var claims = new Claim[]
{
new Claim(ClaimTypes.Name, user.Id),
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Role, user.Role), // there can be more roles, but you get the idea
// etc.
};
// Establish identity and login
var identity = new ClaimsIdentity(claims, "CookieAuthentication");
HttpContext.Current.GetOwinContext().Authentication.SignIn(identity);
But I also know I could be using ASP.NET Identity (just without Entity Framework stuff), and just implement IUser, IUserStore, IRoleStore (and whatever else is minimally required), and use an existing, established framework from Microsoft for handling this. The argument would be that this is more in line with current standards, and could potentially be extended easier for other types of authentication (if, say, a local username/password, or Google/Facebook become other allowed authentication options eventually, in addition to the current, ServerVariables-based setup).
Any advice from people who've been down this path before? Should I treat the server variable injected data as custom middleware and leverage it via ASP.NET Identity, or just not worry about where to fit it in that world, and go in a more of a "purist" approach as described above?
p.s. I'm using ASP.NET 4.6.1, and not the new ASP.NET Core.
Upvotes: 4
Views: 2147
Reputation: 62260
I have similar saturation. I do not want to use entire ASP.Net Identity, because I need to authenticate user again our external authentication.
So I just use OWIN Claim Authentication which basically creates Authentication cookie with Claims; Similar to Form Authentication we used in the old days.
public class OwinAuthenticationService
{
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.ToString()),
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);
}
}
Note: I have Angular using both MVC and Web API, so I return 404 message for REST instead of 404 Page.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
if (!IsApiRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
}
private static bool IsApiRequest(IOwinRequest request)
{
string apiPath = VirtualPathUtility.ToAbsolute("~/api/");
return request.Uri.LocalPath.ToLower().StartsWith(apiPath);
}
}
Upvotes: 3