All,
I've got a security server which sole purpose is to provide bearer tokens from a single endpoint: http://example.com/token
Example request:
POST http://example.com/token HTTP/1.1
User-Agent: Fiddler
Content-Type: x-www-form-urlencoded
Host: example.com
Content-Length: 73
grant_type=password&[email protected]&password=examplePassword
Example response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 16 Aug 2016 12:04:39 GMT
{
"access_token": "xxxx",
"token_type": "bearer",
"expires_in": 17999,
"refresh_token": "xxxx",
".issued": "Tue, 16 Aug 2016 12:04:38 GMT",
".expires": "Tue, 16 Aug 2016 17:04:38 GMT"
}
We have an angular application which uses this endpoint to authenticate, and does so just fine.
What we are trying to achieve without much success is to create an MVC application which uses the same server to authenticate, we'd like the code to sit on top of Identity 2.0 if possible.
In our AccountController
(example project) we have our Login(LoginModel model)
method which handles login and looks like this (same as example project template):
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
We have our own implemention of IUserStore, UserManager, SignInManager.
I've considered overriding
public Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout) on `SignInManager<,>` and make a web call across to the security server.
The default implementation of PasswordSignInAsync
calls UserManager.FindByNameAsync
however this would mean I'd have to expose a lookup method on my security server to confirm a username exists which really doesn't sound good.
I must be missing something and I know it wouldn't be this complicated, our MVC app needs to use cookie authentication but also maintain the bear token for subsequent calls to our other resource server.
(I appreciate I might be mixing up technologies here, hence the question).
This is also running on OWIN.
In this case, I don't think you should use Identity 2.0 in your MVC application. You should create an AuthenticationClient
to call your authentication server, you could also use this library to build such a client https://www.nuget.org/packages/Thinktecture.IdentityModel.Client/
public class AuthenticationClient {
public ClaimsIdentity GetClaimsIdentity(string username, string password) {
//Call your authentication server to get your token and also claims associated with your identity.
//You can look at an example code how to do it: https://github.com/IdentityServer/IdentityServer3.Samples/blob/master/source/Clients/ConsoleResourceOwnerClient/Program.cs
//and create a ClaimsIdentity object out of those information
var identity = GetIdentity();
//The key point here is to add AccessToken and RefreshToken as custom claims to your identity so you retrieve these tokens back on subsequent requests.
identity.AddClaim(new Claim("access_token", accessToken));
identity.AddClaim(new Claim("refresh_token", refreshToken));
}
}
This will fulfill your requirements:
Use cookie authentication but also maintain the bear token for subsequent calls to our other resource server.
Your Login
method on AccountController
should be like this:
public ActionResult Login(LoginModel model)
{
var identity = authenticationClient.GetClaimsIdentity(model.UserName, model.Password);
if (identity == null) {
return new HttpUnauthorizedResult();
}
//Sign in the user
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(identity);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
I assume that you already register this middleware to use Cookie authentication:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
Now for all subsequent requests, you could retrieve back the access token to call your resource server from your ClaimsIdentity:
User.Identity.Claims.FirstOrDefault(x => x.Type == "access_token");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With