问题
I have an ASP.NET Core 2.1 WebApi, in which I have implemented JWT authentication. The user calls api/authentication/authenticate
, passes their username/password in the message body, and gets back a JWT in return which they then use to access the service.
I also need the API to accept Windows authentication -- the user will call api/authentication/windows
passing no user information, the service will check they are in the list of authorized users as listed in the web.config file (if I am hosting in IIS). If so, return a JWT token and the user can use that to access the service.
Currently I'm thinking about this...
- The
api/authentication/windows
method will get the username from the request - Check the username against the list of authorized users. If they are on it, return a token. If not, go to (3)
- Check against any groups in the authorized users list. If they are a member, return a token. If not, return a 401 Unauthorized error
Is this the correct way to approach this?
Very similar (unanswered) question here: Generate JWT token on successful authentication with Windows Authentication
回答1:
If you want to enable both JWT and AD authentication ,in my option, you still need to validate the user's credential(username/password) against Active Directory in web api :
https://www.brechtbaekelandt.net/blog/post/authenticating-against-active-directory-with-aspnet-core-2-and-managing-users
Pass just username won't work since there is no authenticated user context in web api .
After validating user credential , you can generate jwt token as usual , for example if using HS256:
private string BuildToken()
{
var claims = new[] {
new Claim(JwtRegisteredClaimNames.NameId,"name1"),
new Claim(JwtRegisteredClaimNames.Sub,"name1"),
new Claim("customer","customer1"),
new Claim(JwtRegisteredClaimNames.Email,"wuxiyuan@sina,com"),
new Claim("role","user"),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Youkey"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken("name1",
"name1",
claims,
expires: DateTime.Now.AddDays(1),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
回答2:
- To get the username from the request to the route
api/authentication/windows
you should activate windows authentication for the asp.net core application. You can achieve that either modifying the web.config or enable the windows authentication in IIS.
<configuration>
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="true" />
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</configuration>
- For debugging purposes modify
launchSettings.json
:
"iisSettings": {
"windowsAuthentication": true,
}
Leave the anonymous authentication activated:
<anonymousAuthentication enabled="
true" />
. It is necessary in order the JWT authentication works properly for the routeapi/authentication/authenticate
Make sure that the attribute
forwardWindowsAuthToken
of the aspNetCore element inweb.config
is not deactivated:forwardWindowsAuthToken="true"
or remove it because of the default value (true)Add IISIntegration to the webHostBuilder unless you use a default builder:
WebHost.CreateDefaultBuilder(args)
- UseIISIntegration is called implicit within this extension method.Add an Authorize attribute for the
POST
-method which will be mapped with the routeapi/authentication/windows
Test the authentication (sending windows-credentials):
var handler = new System.Net.Http.HttpClientHandler()
{
Credentials = System.Net.CredentialCache.DefaultCredentials
};
var httpClient = new System.Net.Http.HttpClient(handler)
{
BaseAddress = new Uri("http://localhost")
};
var response = await httpClient.PostAsync("api/authentication/windows", null);
or using XMLHttpRequest object:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost/api/authentication/windows', true);
xhr.withCredentials = true;
xhr.send();
- Get the user name in the controller:
var username = HttpContext.User.FindFirst(System.Security.Claims.ClaimTypes.Name)?.Value;
- Generate a JWT-Token, e.g using jose-jwt:
var claims = new Dictionary<string, object>
{
["jti"] = Guid.NewGuid(),
["sub"] = username,
["exp"] = DateTimeOffset.UtcNow.AddMinutes(100).ToUnixTimeSeconds()
};
var secretKey = new byte[] { 164, 60, 194, 0, 161 };
var headers = new Dictionary<string, object>
{
["alg"] = "HS512",
["typ"] = "JWT"
};
var token = JWT.Encode(claims, secretKey, JwsAlgorithm.HS512, headers);
来源:https://stackoverflow.com/questions/57711147/use-windows-auth-to-authenticate-user-and-then-generate-jwt-in-aspnet-core-2-1