用.Net Code 3.1做网站,同时提供API,怎么做身份验证?

2019-12-19 23:33发布

目标是做一个网站系统实现很多功能。
其中几个功能被要求使用时必须用桌面应用程序,不能用网站,所以会有好几个单独客户端。
但是所有的操作都需要身份验证,要有角色限制。
系统不是很复杂,所以不想把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";这行导致的

2条回答
Rolldiameter
2楼-- · 2019-12-20 00:23

https://github.com/linianhui/oidc.example 给你个示例,ids4做的认证+授权服务,wpf,uwp,js,console等类型的客户端应用。

查看更多
forever°为你锁心
3楼-- · 2019-12-20 00:31

给你一个简单的实现思路,其实我们说的认证,简单的就是说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的小伙伴,最近准备一起维护一个技术类的干货公众号,覆盖各种语言,欢迎大家关注支持,一起交流、一起进步,谢谢!!哈哈,博主不要打我,我们也是在学习,谢谢!

查看更多
登录 后发表回答