问题:
目标是做一个网站系统实现很多功能。
其中几个功能被要求使用时必须用桌面应用程序,不能用网站,所以会有好几个单独客户端。
但是所有的操作都需要身份验证,要有角色限制。
系统不是很复杂,所以不想把API和网站分开,感觉分开后会很麻烦,我也只会用.Net写网站
目前的结果是用IdentityServer4管理账户,但是那个网站只能单独作为客户端或者单独提供资源,这个根据文档都写没问题,但是同时作为客户端和资源的时候总是无法配置成功。应该怎么配置?
或者肯定有更简单的办法,不使用IdentityServer4,直接让.Net Core3.1的API用JWT身份验证,同时访问网站时也可以登录,但是相关示例找不到,官方文档也没有写(或者我不会英文找不到),创建VS2019 创建API的时候根本没有本地身份验证这个模板。
用户管理用得都是自带的 AspNetCore.Identity
.NetCode配置资源的代码是:
services.AddAuthentication(“Bearer”).AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "MainApi";
});
配置客户端的代码是:
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "oidc";
options.DefaultScheme = "Cookies";
}).AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("MainApi");
options.Scope.Add("Roles");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role
};
});
但是吧他们一个一个写一通过API访问被保护资源就直接返回identitysrever登陆页面的源代码
如果这样合起来写的话
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "oidc";
options.DefaultScheme = "Cookies";
options.DefaultAuthenticateScheme = "Bearer";
}).AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("MainApi");
options.Scope.Add("Roles");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role
};
}).AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "MainApi";
});
会一直循环在identityServer登陆后选择资源的那个页面出不去,根据实验是options.DefaultAuthenticateScheme = "Bearer";
这行导致的
回答1:
https://github.com/linianhui/oidc.example 给你个示例,ids4做的认证+授权服务,wpf,uwp,js,console等类型的客户端应用。
回答2:
给你一个简单的实现思路,其实我们说的认证,简单的就是说API接口知道是谁在访问,并且判断是否允许其访问。
1、接口和用户需要一个身份标志,在调用接口的时候就需要传递这个身份标志来确认
怎样生成获取这个身份标志呢?当人也是提高一个专门获取身份接口的,下面的例子我用户一个登陆接口来说明
public object Login(string strUser, string strPwd)
{
if (!ValidateUser(strUser, strPwd))
{
return new { bRes = false };
}
//// 生成身份标志的票据,并将这个票据信息加密后传递到前端
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, strUser, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", strUser, strPwd), FormsAuthentication.FormsCookiePath);
////返回登录结果、用户信息、用户验证票据信息
var oUser = new UserInfo { bRes = true, UserName = strUser,Ticket = FormsAuthentication.Encrypt(ticket) };
return oUser;
}
2、前端收到至二个身份标志票据后,保存起来,然后在每一次调用其他接口时都带上该标志
在传递的身份标志通过header传递:
$.ajax({
type: "get",
url: "http://localhost:60793/Default/GetNum1",
data: {},
beforeSend: function (XHR) {
//发送ajax请求之前向http的head里面加入验证信息
XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket);
}
});
3、PAI准备,首先需要重写Attribute
public class AuthFilterAttribute : Attribute, IAuthenticationFilter
{
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
try
{
var authorization = context.Request.Headers.Authorization;
if ((authorization != null) && (authorization.Parameter != null))
{
var Parameter = authorization.Parameter;
if (!string.IsNullOrEmpty(Parameter) && Parameter != "null" && Parameter != "undefined")
{
var encryptTicket = authorization.Parameter;
//解密Ticket
var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
//从Ticket里面获取用户名和密码
var index = strTicket.IndexOf("&");
string strUser = strTicket.Substring(0, index);
string strPwd = strTicket.Substring(index + 1);
//用户名登录验证
/// 此处可以加一些验证逻辑,比如用户密码,令牌的有效期等等验证,完全自定义
}
}
}
catch (Exception e)
{
throw e;
}
return Task.FromResult(0);
}
4、需要验证的接口加入验证注解:
[System.Web.Http.Authorize()]
public int GetNum1()
{
return 1;
}
5、通过上面的步骤,每次调用GetNum1接口都必须要传递身份标签,并且只有验证通过后才可以进入接口内部实现
6、其实说了这么多,简单说,就是一个oauth认证原理罢了
最后的最后,欢迎加入公众号,分享一些技术干货,谢谢
各位程序员们,我们是一群工作7-10的小伙伴,最近准备一起维护一个技术类的干货公众号,覆盖各种语言,欢迎大家关注支持,一起交流、一起进步,谢谢!!哈哈,博主不要打我,我们也是在学习,谢谢!