app.UseIdentityServerBearerTokenAuthentication 和用户信息
app.UseIdentityServerBearerTokenAuthentication and UserInfo
对于我的 WebAPI,我使用的是:
public void ConfigureAuth(IAppBuilder 应用程序)
{
app.UseIdentityServerBearerTokenAuthentication( new IdentityServerBearerTokenAuthenticationOptions
{
Authority = ConfigurationManager.AppSettings[ "ida:Authority" ],
RequiredScopes = new[ ]
{
"XXXXAPI"
}
} );
}
我的身份验证没问题,但我需要获取 UserInfo 端点提供的我的角色和其他信息。
UseIdentityServerBearerTokenAuthentication 是否会自动执行此操作,或者是否存在像 OpenIdConnectAuthenticationNotifications.AuthroizationCodeReceived 这样的事件我应该用来设置 ClaimsIdentity?
您必须使用 OAuth2+JWT 和一些自定义配置来保存用户角色和访问令牌中的其他声明。
在Web.config
中添加这些值
<appSettings>
<add key="as:AudienceId" value="414e1927a3884f68abc79f7283837fd1" />
<add key="as:AudienceSecret" value="qMCdFDQuF23RV1Y-1Gq9L3cF3VmuFwVbam4fMTdAfpo" />
</appSettings>
写一个 CustomJwtFormat class
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using System;
using System.Configuration;
using System.IdentityModel.Tokens;
using Thinktecture.IdentityModel.Tokens;
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
}
创建自定义 authenticationProvider
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (AuthRepository _repo = new AuthRepository())
{
User user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("unique_name", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
配置您的自定义设置
private static void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new ApplicationOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost/")
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private static void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = "http://localhost/";
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
public void Configuration(IAppBuilder app(
{
app.UseAutofacMvc();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
//other codes
}
如果想从access token中获取userInfo,按如下方式进行:
public static string GetUserNameFromOAuth(HttpRequestMessage Request)
{
if (Request.Headers.Contains("Authorization"))
{
var authHeader = Request.Headers.GetValues("Authorization");
var authEncoded = authHeader.FirstOrDefault();
var authList = authEncoded.Split(' ');
var payload = authList[1];
var symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
string token = JWT.JsonWebToken.Decode(payload, keyByteArray);
var jsonObject = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(token);
var userName = jsonObject.FirstOrDefault(p => p.Key == "unique_name").Value;
return userName;
}
return "";
}
在邮递员中测试:
app.UseIdentityServerBearerTokenAuthentication 会自动设置角色和范围。
由于某些未知原因,仅当调用方为 UserInfoEndpoint 时,我才从 UserService 的 GetProfileDataAsync 返回数据。一旦我摆脱了这段代码,所有角色都会自动填充。
对于我的 WebAPI,我使用的是: public void ConfigureAuth(IAppBuilder 应用程序) {
app.UseIdentityServerBearerTokenAuthentication( new IdentityServerBearerTokenAuthenticationOptions
{
Authority = ConfigurationManager.AppSettings[ "ida:Authority" ],
RequiredScopes = new[ ]
{
"XXXXAPI"
}
} );
}
我的身份验证没问题,但我需要获取 UserInfo 端点提供的我的角色和其他信息。
UseIdentityServerBearerTokenAuthentication 是否会自动执行此操作,或者是否存在像 OpenIdConnectAuthenticationNotifications.AuthroizationCodeReceived 这样的事件我应该用来设置 ClaimsIdentity?
您必须使用 OAuth2+JWT 和一些自定义配置来保存用户角色和访问令牌中的其他声明。
在Web.config
中添加这些值<appSettings> <add key="as:AudienceId" value="414e1927a3884f68abc79f7283837fd1" /> <add key="as:AudienceSecret" value="qMCdFDQuF23RV1Y-1Gq9L3cF3VmuFwVbam4fMTdAfpo" /> </appSettings>
写一个 CustomJwtFormat class
using Microsoft.Owin.Security; using Microsoft.Owin.Security.DataHandler.Encoder; using System; using System.Configuration; using System.IdentityModel.Tokens; using Thinktecture.IdentityModel.Tokens; public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket> { private readonly string _issuer = string.Empty; public CustomJwtFormat(string issuer) { _issuer = issuer; } public string Protect(AuthenticationTicket data) { if (data == null) { throw new ArgumentNullException("data"); } string audienceId = ConfigurationManager.AppSettings["as:AudienceId"]; string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"]; var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64); var signingKey = new HmacSigningCredentials(keyByteArray); var issued = data.Properties.IssuedUtc; var expires = data.Properties.ExpiresUtc; var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey); var handler = new JwtSecurityTokenHandler(); var jwt = handler.WriteToken(token); return jwt; } }
创建自定义 authenticationProvider
using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.Owin.Security; using Microsoft.Owin.Security.OAuth; public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider { public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); return Task.FromResult<object>(null); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); using (AuthRepository _repo = new AuthRepository()) { User user = await _repo.FindUser(context.UserName, context.Password); if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("unique_name", context.UserName)); identity.AddClaim(new Claim("role", "user")); context.Validated(identity); } }
配置您的自定义设置
private static void ConfigureOAuthTokenGeneration(IAppBuilder app) { OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { //For Dev enviroment only (on production should be AllowInsecureHttp = false) AllowInsecureHttp = true, TokenEndpointPath = new PathString("/oauth/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new ApplicationOAuthProvider(), AccessTokenFormat = new CustomJwtFormat("http://localhost/") }; // OAuth 2.0 Bearer Access Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); } private static void ConfigureOAuthTokenConsumption(IAppBuilder app) { var issuer = "http://localhost/"; string audienceId = ConfigurationManager.AppSettings["as:AudienceId"]; byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]); // Api controllers with an [Authorize] attribute will be validated with JWT app.UseJwtBearerAuthentication( new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, AllowedAudiences = new[] { audienceId }, IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] { new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret) } }); } public void Configuration(IAppBuilder app( { app.UseAutofacMvc(); ConfigureOAuthTokenGeneration(app); ConfigureOAuthTokenConsumption(app); //other codes }
如果想从access token中获取userInfo,按如下方式进行:
public static string GetUserNameFromOAuth(HttpRequestMessage Request) { if (Request.Headers.Contains("Authorization")) { var authHeader = Request.Headers.GetValues("Authorization"); var authEncoded = authHeader.FirstOrDefault(); var authList = authEncoded.Split(' '); var payload = authList[1]; var symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"]; var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64); var signingKey = new HmacSigningCredentials(keyByteArray); string token = JWT.JsonWebToken.Decode(payload, keyByteArray); var jsonObject = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(token); var userName = jsonObject.FirstOrDefault(p => p.Key == "unique_name").Value; return userName; } return ""; }
在邮递员中测试:
app.UseIdentityServerBearerTokenAuthentication 会自动设置角色和范围。
由于某些未知原因,仅当调用方为 UserInfoEndpoint 时,我才从 UserService 的 GetProfileDataAsync 返回数据。一旦我摆脱了这段代码,所有角色都会自动填充。