區(qū)別OpenId: Authentication :認(rèn)證
OpenID當(dāng)你需要訪問A網(wǎng)站的時(shí)候,A網(wǎng)站要求你輸入你的OpenId,即可跳轉(zhuǎn)到你的OpenId服務(wù)網(wǎng)站,輸入用戶名和密碼之后,再調(diào)回A網(wǎng)站,則認(rèn)證成功。 OAuth2.0OAuth是一個(gè)關(guān)于授權(quán)的開放網(wǎng)絡(luò)協(xié)議,允許用戶讓第三方應(yīng)用訪問該用戶在在某一網(wǎng)站上的資源,而無需提供用戶名和密碼給第三方。
OpenID --(OpenID Connect) 簡(jiǎn)稱OIDCOpenID Connect是OpenID的升級(jí)版,簡(jiǎn)稱OIDC,是2014年初發(fā)布的開放標(biāo)準(zhǔn),定義了一種基于OAuth2的可互操作的方式來來提供用戶身份認(rèn)證。在OIDC中,應(yīng)用程序不必再為每個(gè)客戶端構(gòu)建不同的協(xié)議,而是可以將一個(gè)協(xié)議提供給多個(gè)客戶端,它還使用了JOSN簽名和加密規(guī)范,用來在傳遞攜帶簽名和加密的信息,并使用簡(jiǎn)單的REST/JSON消息流來實(shí)現(xiàn),和之前任何一種身份認(rèn)證協(xié)議相比,開發(fā)者都可以輕松的集成。簡(jiǎn)單說 OIDC是在OAuth2.0之上的一個(gè)擴(kuò)展 ID Tokens IdentityServer4現(xiàn)在的應(yīng)用開發(fā)層出不窮,基于瀏覽器的網(wǎng)頁(yè)應(yīng)用,基于微信的公眾號(hào)、小程序,基于IOS、Android的App,基于Windows系統(tǒng)的桌面應(yīng)用和UWP應(yīng)用等等,這么多種類的應(yīng)用,就給應(yīng)用的開發(fā)帶來的挑戰(zhàn),我們除了分別實(shí)現(xiàn)各個(gè)應(yīng)用外,我們還要考慮各個(gè)應(yīng)用之間的交互,通用模塊的提煉,其中身份的認(rèn)證和授權(quán)就是每個(gè)應(yīng)用必不可少的的一部分。而現(xiàn)在的互聯(lián)網(wǎng),對(duì)于信息安全要求又十分苛刻,所以一套統(tǒng)一的身份認(rèn)證和授權(quán)就至關(guān)重要。
JwtBearer 認(rèn)證
Bearer認(rèn)證(也叫做令牌認(rèn)證)是一種HTTP認(rèn)證方案,其中包含的安全令牌的叫做Bearer Token。因此Bearer認(rèn)證的核心是Token。那如何確保Token的安全是重中之重。一種方式是使用Https,另一種方式就是對(duì)Token進(jìn)行加密簽名。而JWT就是一種比較流行的Token編碼方式。 JWT(Json Web Token)
JWT有三部分組成:
Header:由alg和typ組成,alg是algorithm的縮寫,typ是type的縮寫,指定token的類型。該部分使用Base64Url編碼。 ASP.NET授權(quán)認(rèn)證(OWIN、Katana)ASP.NET現(xiàn)有的的asp.net是成熟且功能豐富的運(yùn)行時(shí)和開發(fā)人員編程模型,同時(shí)這個(gè)框架已整體式,各種不同邏輯的功能單元都緊密耦合在System.web.dll程序集中。作為更大的.NET Framework更新周期基本以年為單位。開發(fā)團(tuán)隊(duì)采用了幾個(gè)進(jìn)化步驟將ASP.NET作為可插入的一系列組件而不是單一框架。
OWINOWIN定義了.NET Web服務(wù)器和Web應(yīng)用程序之間的標(biāo)準(zhǔn)接口。OWIN接口的目標(biāo)是分離服務(wù)器和應(yīng)用程序。 Katana用于Microsoft服務(wù)器和框架的OWIN實(shí)現(xiàn) 優(yōu)勢(shì)
結(jié)構(gòu)
Owin OAuth代碼實(shí)現(xiàn) ///啟動(dòng)配置
public class Startup
{
public void Configuration(IAppBuilder app)
{
//授權(quán)認(rèn)證
ConfigAuth(app, container);
app.UseWebApi(config);
}
private void ConfigAuth(IAppBuilder app,IContainer container)
{
app.CreatePerOwinContext(()=> PatternDbContext.Create());
app.CreatePerOwinContext<ApplicationRoleManagers>(CreateRoleManager);
app.CreatePerOwinContext<ApplicationUserManagers>(CreateUserManager);
OAuthAuthorizationServerOptions option = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
AuthenticationMode = AuthenticationMode.Active,
TokenEndpointPath = new PathString("/token"),//獲取 access_token 授權(quán)服務(wù)請(qǐng)求地址
AuthorizeEndpointPath = new PathString("/authorize"), //獲取 authorization_code 授權(quán)服務(wù)請(qǐng)求地址
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new OpenAuthorizationServerProvider(), //access_token 相關(guān)授權(quán)服務(wù)
AuthorizationCodeProvider = new OpenAuthorizationCodeProvider(), //authorization_code 授權(quán)服務(wù)
//RefreshTokenProvider = new OpenRefreshTokenProvider() ,//refresh_token 授權(quán)服務(wù)
AccessTokenProvider = new OpenAccessTokenProvider()
};
//啟用授權(quán)服務(wù)器,產(chǎn)生token
app.UseOAuthAuthorizationServer(option);
//啟用授權(quán)認(rèn)證
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class OpenAuthorizationServerProvider:OAuthAuthorizationServerProvider
{
/// <summary>
/// 用戶名密碼授權(quán)處理
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManagers>();
var roleManager = context.OwinContext.GetUserManager<ApplicationRoleManagers>();
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//查詢用戶是否存在
var userModel = new UserModel() { UserName = context.UserName, Password = context.Password };
var user = await userManager.FindAsync(userModel.UserName,userModel.Password);
if (user==null)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
return;
}
var IpAddress = context.Request.RemoteIpAddress;
var db = context.OwinContext.Get<PatternDbContext>();
var result = db.Set<DeviceAddress>().FirstOrDefault(d => d.Address == IpAddress);
if (result == null)
{
context.SetError("invalid_client", IpAddress + "client is not valid");
return;
}
//查詢用戶角色
var roles = await userManager.GetRolesAsync(user.Id);
//組裝用戶權(quán)限等聲明信息
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim("userName", context.UserName));
foreach (var role in roles)
{
var roleTemp = await roleManager.FindByNameAsync(role);//獲取角色對(duì)應(yīng)的權(quán)限
foreach (var permission in roleTemp.Permissions)
{
identity.AddClaim(new Claim("Permission", permission.Info));
}
identity.AddClaim(new Claim(ClaimTypes.Role, role));
}
//額外顯示屬性
var props = new AuthenticationProperties(new Dictionary<string, string>
{
//{"as:client_id",context.ClientId??string.Empty },
{"userName",context.UserName },
{"userId",user.Id }
});
var ticket = new AuthenticationTicket(identity, props);
//校驗(yàn)生成token
context.Validated(ticket);
}
}
///自定義授權(quán)
public class MyAuthorizeAttribute:AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
//獲取用戶對(duì)象
IPrincipal principal = actionContext.ControllerContext.RequestContext.Principal;
if (principal == null)
{
var token = actionContext.Request.Headers.Authorization.Parameter;
using (PatternDbContext db=new PatternDbContext())
{
var tokenStr = db.LoginStates.FirstOrDefault(t => t.TokenStr == token);
if (tokenStr != null)
{
tokenStr.IsOnline = false;
tokenStr.LogoutDate = DateTime.Now;
db.SaveChanges();
}
}
return false;
}
//獲取權(quán)限聲明
var claims = (principal.Identity as ClaimsIdentity).Claims.Where(d=>d.Type=="Permission").Select(d=>d.Value);
if (claims != null)
{
if((Permission!=null)&&! claims.Contains(Permission,StringComparer.OrdinalIgnoreCase))
{
return false;
}
}
else
{
return false;
}
return base.IsAuthorized(actionContext);
}
}ASP.NET CORE授權(quán)認(rèn)證(IdentityServer4)認(rèn)證服務(wù)器//注冊(cè)認(rèn)證服務(wù)器 services.AddIdentityServer() .AddDeveloperSigningCredential() .AddMongoRepository() //.AddMongoDbForAspIdentity<ApplicationUser, ApplicationRole>(Configuration) .AddClients() .AddPersistedGrants() .AddIdentityApiResources() .AddAspNetIdentity<ApplicationUser>() .AddResourceOwnerValidator<CustomResourceOwnerPasswordValidtor<ApplicationUser,ApplicationRole>>() .AddProfileService<CusromProfileService<ApplicationUser>>() .AddCorsPolicyService< CorsPolicyService>() ; 資源服務(wù)//添加認(rèn)證
services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie("Cookies")
.AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secret")),
ValidateLifetime = true,
};
var configUrl = new ConfigurationBuilder().AddJsonFile("host.json", false, true).Build()["urls"];
//var url = Configuration["urls"];
options.Authority = configUrl;
options.RequireHttpsMetadata = false;
options.Audience = "KnowBaseApi";
});MVC客戶端services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies",opt=>
{
opt.LoginPath = "/Login";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://10.53.28.168:5010";
options.RequireHttpsMetadata = false;
options.CallbackPath = "/home";
options.ClientId = "AntennaKnowbaseApi";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
options.Scope.Add("profile");
//options.ClaimActions.MapJsonKey("website", "website");
});
|
|
|