我正在嘗試使用授權碼流在AspNet Core上實現Identity Server 4。身份服務器4授權碼流程示例
事情是,github上的IdentityServer4存儲庫有幾個樣本,但沒有授權碼流程。
是否有人有關於如何實施的授權代碼流程與身份驗證服務器4和MVC中的客戶端消費它?
我正在嘗試使用授權碼流在AspNet Core上實現Identity Server 4。身份服務器4授權碼流程示例
事情是,github上的IdentityServer4存儲庫有幾個樣本,但沒有授權碼流程。
是否有人有關於如何實施的授權代碼流程與身份驗證服務器4和MVC中的客戶端消費它?
這裏有一個授權碼流與身份服務器4和MVC客戶端來使用它的實現。
IdentityServer4可以使用client.cs文件註冊我們的MVC客戶端,它的Client,ClientSecret,允許的許可類型(授權碼在這種情況下),和我們的客戶的RedirectUri:
public class Clients
{
public static IEnumerable<Client> Get()
{
var secret = new Secret { Value = "mysecret".Sha512() };
return new List<Client> {
new Client {
ClientId = "authorizationCodeClient2",
ClientName = "Authorization Code Client",
ClientSecrets = new List<Secret> { secret },
Enabled = true,
AllowedGrantTypes = new List<string> { "authorization_code" }, //DELTA //IdentityServer3 wanted Flow = Flows.AuthorizationCode,
RequireConsent = true,
AllowRememberConsent = false,
RedirectUris =
new List<string> {
"http://localhost:5436/account/oAuth2"
},
PostLogoutRedirectUris =
new List<string> {"http://localhost:5436"},
AllowedScopes = new List<string> {
"api"
},
AccessTokenType = AccessTokenType.Jwt
}
};
}
}
該類在IdentityServer4項目Startup.cs的ConfigurationServices方法中被引用:
public void ConfigureServices(IServiceCollection services)
{
////Grab key for signing JWT signature
////In prod, we'd get this from the certificate store or similar
var certPath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "SscSign.pfx");
var cert = new X509Certificate2(certPath);
// configure identity server with in-memory stores, keys, clients and scopes
services.AddDeveloperIdentityServer(options =>
{
options.IssuerUri = "SomeSecureCompany";
})
.AddInMemoryScopes(Scopes.Get())
.AddInMemoryClients(Clients.Get())
.AddInMemoryUsers(Users.Get())
.SetSigningCredential(cert);
services.AddMvc();
}
作爲參考,這裏是上面提到的用戶和作用域類:
public static class Users
{
public static List<InMemoryUser> Get()
{
return new List<InMemoryUser> {
new InMemoryUser {
Subject = "1",
Username = "user",
Password = "pass123",
Claims = new List<Claim> {
new Claim(ClaimTypes.GivenName, "GivenName"),
new Claim(ClaimTypes.Surname, "surname"), //DELTA //.FamilyName in IdentityServer3
new Claim(ClaimTypes.Email, "[email protected]"),
new Claim(ClaimTypes.Role, "Badmin")
}
}
};
}
}
public class Scopes
{
// scopes define the resources in your system
public static IEnumerable<Scope> Get()
{
return new List<Scope> {
new Scope
{
Name = "api",
DisplayName = "api scope",
Type = ScopeType.Resource,
Emphasize = false,
}
};
}
}
MVC應用程序需要兩種控制器方法。第一種方法啓動服務提供商(SP-Initiated)工作流程。它創建一個狀態值,將其保存在基於Cookie的身份驗證中間件中,然後將瀏覽器重定向到IdentityProvider(IdP) - 我們的IdentityServer4項目。
public ActionResult SignIn()
{
var state = Guid.NewGuid().ToString("N");
//Store state using cookie-based authentication middleware
this.SaveState(state);
//Redirect to IdP to get an Authorization Code
var url = idPServerAuthUri +
"?client_id=" + clientId +
"&response_type=" + response_type +
"&redirect_uri=" + redirectUri +
"&scope=" + scope +
"&state=" + state;
return this.Redirect(url); //performs a GET
}
作爲參考,這裏的常數和即時存檔方法利用以上:
//Client and workflow values
private const string clientBaseUri = @"http://localhost:5436";
private const string validIssuer = "SomeSecureCompany";
private const string response_type = "code";
private const string grantType = "authorization_code";
//IdentityServer4
private const string idPServerBaseUri = @"http://localhost:5000";
private const string idPServerAuthUri = idPServerBaseUri + @"/connect/authorize";
private const string idPServerTokenUriFragment = @"connect/token";
private const string idPServerEndSessionUri = idPServerBaseUri + @"/connect/endsession";
//These are also registered in the IdP (or Clients.cs of test IdP)
private const string redirectUri = clientBaseUri + @"/account/oAuth2";
private const string clientId = "authorizationCodeClient2";
private const string clientSecret = "mysecret";
private const string audience = "SomeSecureCompany/resources";
private const string scope = "api";
//Store values using cookie-based authentication middleware
private void SaveState(string state)
{
var tempId = new ClaimsIdentity("TempCookie");
tempId.AddClaim(new Claim("state", state));
this.Request.GetOwinContext().Authentication.SignIn(tempId);
}
第二MVC動作方法由IdenityServer4用戶輸入他們的憑證,並檢查任何授權盒之後被調用。操作方法:
這裏的方法:
[HttpGet]
public async Task<ActionResult> oAuth2()
{
var authorizationCode = this.Request.QueryString["code"];
var state = this.Request.QueryString["state"];
//Defend against CSRF attacks http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html
await ValidateStateAsync(state);
//Exchange Authorization Code for an Access Token by POSTing to the IdP's token endpoint
string json = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(idPServerBaseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", grantType)
,new KeyValuePair<string, string>("code", authorizationCode)
,new KeyValuePair<string, string>("redirect_uri", redirectUri)
,new KeyValuePair<string, string>("client_id", clientId) //consider sending via basic authentication header
,new KeyValuePair<string, string>("client_secret", clientSecret)
});
var httpResponseMessage = client.PostAsync(idPServerTokenUriFragment, content).Result;
json = httpResponseMessage.Content.ReadAsStringAsync().Result;
}
//Extract the Access Token
dynamic results = JsonConvert.DeserializeObject<dynamic>(json);
string accessToken = results.access_token;
//Validate token crypto
var claims = ValidateToken(accessToken);
//What is done here depends on your use-case.
//If the accessToken is for calling a WebAPI, the next few lines wouldn't be needed.
//Build claims identity principle
var id = new ClaimsIdentity(claims, "Cookie"); //"Cookie" matches middleware named in Startup.cs
//Sign into the middleware so we can navigate around secured parts of this site (e.g. [Authorized] attribute)
this.Request.GetOwinContext().Authentication.SignIn(id);
return this.Redirect("/Home");
}
檢查收到的州是否您期望的幫助抵禦CSRF攻擊:
private async Task<AuthenticateResult> ValidateStateAsync(string state)
{
//Retrieve state value from TempCookie
var authenticateResult = await this.Request
.GetOwinContext()
.Authentication
.AuthenticateAsync("TempCookie");
if (authenticateResult == null)
throw new InvalidOperationException("No temp cookie");
if (state != authenticateResult.Identity.FindFirst("state").Value)
throw new InvalidOperationException("invalid state");
return authenticateResult;
}
這ValidateToken方法使用微軟的System.IdentityModel和System.IdentityModel.Tokens.Jwt:http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html
這ValidateStateAsync方法收到的國家進行比較,以什麼在Cookie中保存中間件關閉圖書館檢查智威湯遜是否正確簽署。
private IEnumerable<Claim> ValidateToken(string token)
{
//Grab certificate for verifying JWT signature
//IdentityServer4 also has a default certificate you can might reference.
//In prod, we'd get this from the certificate store or similar
var certPath = Path.Combine(Server.MapPath("~/bin"), "SscSign.pfx");
var cert = new X509Certificate2(certPath);
var x509SecurityKey = new X509SecurityKey(cert);
var parameters = new TokenValidationParameters
{
RequireSignedTokens = true,
ValidAudience = audience,
ValidIssuer = validIssuer,
IssuerSigningKey = x509SecurityKey,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
//Validate the token and retrieve ClaimsPrinciple
var handler = new JwtSecurityTokenHandler();
SecurityToken jwt;
var id = handler.ValidateToken(token, parameters, out jwt);
//Discard temp cookie and cookie-based middleware authentication objects (we just needed it for storing State)
this.Request.GetOwinContext().Authentication.SignOut("TempCookie");
return id.Claims;
}
包含這些源文件工作溶液駐留在GitHub在https://github.com/bayardw/IdentityServer4.Authorization.Code
下面是一個示例 - 它使用混合流代替代碼流。但是如果你的客戶端庫支持它(和aspnetcore中間件一樣),混合流量更值得推薦。
你的鏈接斷開。這就是爲什麼你應該把所有重要的部分放在答案本身。 –
嗨,多米尼克,我認爲[這](https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/5_HybridFlowAuthenticationWithApiAccess)是一個更好的鏈接,現在使用? – DavidG
Woa!謝謝你的完整答案! –
我遇到了很多困難,似乎所有的教程/答案似乎都使用了一些較舊的IdentityServer形式。我知道這是直接針對版本4的問題;但是,即使在他們的文檔頁面上也有差異。例如,它們不再具有AddInMemoryScopes,AddImMemoryUsers和沒有標準的User類。 http://docs.identityserver.io/en/release/configuration/startup.html – Adrian