ASP.Net Core, Angular2 and token based authentication
I'm writing a web application using ASP.NET core for the backend / Service and Angular2 as frontend and have Troubles with authentication / authorization.
In ASP.NET core I got just one html page&controller, HomeController with Index which allows anonymous Access ([AllowAnonymous]). This single page delivers the angular2-app to the Client.
All other communication is using ApiControllers (which in ASP.NET core are just normal Controllers, but the Actions on these Controllers expect and send JSON data. For authentication/authorization I want to use jwt tokens. Users, Roles, Claims etc. are stored in an IdentityDbContext using EF core.
Most tutorials I found are outdated, incomplete or refer to 3rd Party OAuth-solutions. I'm not looking for OAuth, I just want a page with username/Passwort and use Tokens to stay logged in since I'm using all API's to get data to and fro the backend. I read lots of tutorials, tried a few helpful libs, but still am confused about how to set up the Middleware chain for token-based security. As far as I understand I Need to add the Services for identity since I want to use IdentityDbContext:
public void ConfigureServices(IServiceCollection services)
{
[...]
services.AddIdentity<IdentityUserEntity, IdentityRoleEntity>()
.AddEntityFrameworkStores<ApplicationDbContext, long>()
.AddDefaultTokenProviders();
[...]
}
But what Middleware do I Need to set up in Configure? Do I Need app.UseIdentity() or would app.UseJwtBearerAuthentication(o) enough? Wouldn't UseIdentity shortcut the authentication before the JwtBearer gets a shot at checking for Tokens??
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
[...]
app.UseIdentity();
[...]
app.UseJwtBearerAuthentication(jwtOptions);
[...]
}
I ask because the Client automagically was authenticated after in my TokenController I performed a call to _signInManager.PasswordSignInAsync(...), even though my client did never receive the jwt. So somehow ASP.NET identity Management found some other way to identify my user after signing in, which of course should not happen.
// simplified controller
public class TokenController : Controller
{
[HttpPost("[action]")]
[AllowAnonymous]
public async Task<JsonResult> Login([FromBody]LoginViewModel loginRequest)
{
var signin = await _signInManager.PasswordSignInAsync(loginRequest.Username, loginRequest.Passwort, true, true);
}
// this will work even though I don't handle any Tokens in the Client yet, so some other authentication mechanism is at work:
[HttpGet("test")]
[Authorize]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}
So how do I implement token based authentication and nothing else?
[UPDATE]
I'd guess I Need to intercept the Cookie authentication event and reject the principal to disable Cookie auth (see https://stackoverflow.com/a/38893778/7021): But for some reason my event handler never gets called.
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = ValidateAsync
}
});
public static async Task ValidateAsync(CookieValidatePrincipalContext context)
{
context.RejectPrincipal();
await context.HttpContext.Authentication.SignOutAsync("BsCookie");
}
More good reads about auth, Cookies and token:
- http://andrewlock.net/exploring-the-cookieauthenticationmiddleware-in-asp-net-core/
- https://stormpath.com/blog/token-authentication-asp-net-core
MS has provided basic jwt token based authentication lib, you can see how to use it here:
https://code.msdn.microsoft.com/How-to-achieve-a-bearer-9448db57
In startup.cs, firstly config Jwt Beare
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseJwtBearerAuthentication(new JwtBearerOptions()
{
TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = TokenAuthOption.Key,
ValidAudience = TokenAuthOption.Audience,
ValidIssuer = TokenAuthOption.Issuer,
// When receiving a token, check that we've signed it.
ValidateIssuerSigningKey = true,
// When receiving a token, check that it is still valid.
ValidateLifetime = true,
// This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time
// when validating the lifetime. As we're creating the tokens locally and validating them on the same
// machines which should have synchronised time, this can be set to zero. Where external tokens are
// used, some leeway here could be useful.
ClockSkew = TimeSpan.FromMinutes(0)
}
});
Now you can add to services
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
Finally, use it in controller, simply add [Authorize("Bearer")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet("GetStaff")]
[Authorize("Bearer")]
public IActionResult GetStaff()
{
List<string> model = new List<string>();
foreach (User user in UserStorage.Users ){
model.Add(user.Username);
}
return Json(model);
}
}
Check full details here: https://github.com/Longfld/ASPNETcoreAngularJWT
链接地址: http://www.djcxy.com/p/3818.html