一次曲折的单点集成之旅

技术一次曲折的单点集成之旅 一次曲折的单点集成之旅原有的系统是mvc 4.6的,要加一个简单的单点系统。经简单比较好,决定选用ids3做service。
集成的方法直接看官方的示例即可:https://

一次曲折的单点集成之旅

原有的系统是mvc 4.6的,要加一个简单的单点系统。经简单比较好,决定选用ids3做服务。

集成的方法直接看官方的示例即可:https://github.com/identity server/identity server 3 .样品

改造涉及到的要点有:

使用授权码PCKE码校验(有点坑)

本地已有用户密码验证

定制登录页面,欢迎页面

nginx反向代理的坑

第一点搜一下,还是能找到资料的。

第2,3点直接看示例代码即可。

第四点真的是一言难尽,以下是详细的跳坑经历。

由于后台服务是部署在(同移民检查员移民检查)上,再通过nginx通过反向代理,配置https证书。

一开始我以为是没办法通过https代理https,所以只是在nignx的启用https。

但这里会有一个很矛盾的地方,整体的站点是https的,但(同移民检查员移民检查)里没有启动用https,直接启用RequireSsl=真会报错。

但如果不设置安全套接层启用,则客户端登录访问的授权点与验证点不一致,直接报404错误。

嗯……头大。

解决办法:

(同移民检查员移民检查)配置好https,使用相同的域名,如果是相同服务器,则使用不同的端口,如1443。

nginx配置https,使用向上游的方式进行反向代理,而不是直接反向代理至服务器端口。

配置如下:

`

上游门户服务器

服务器127 .0 .0 .1:1443;

}

服务器{

监听443 ssl

听[:]:443 SSL;

服务器名xxx.lennon.cn;

# SSL

SSL _ certificate d :/nginx/conf/XXX。列侬。cn。质子交换膜;

SSL _ certificate _ key d :/nginx/conf/XXX。列侬。cn。钥匙;

包括默认/SSL。conf

位置/

proxy _ pass https://test1 _ server

代理集头主机$ host

proxy _ set _ header X-Real-IP $ remote _ addr;

proxy _ set _ header _ X-forward-For $ proxy _ add _ X _ forward _ For;

代理集头-转发-原型$方案;#实际的协议超文本传送协议(超文本传输协议的缩写)还https

代理_下一个_上游错误超时http _ 404 http _ 403

}

# index.php

index.htmlindex.htmindex.php指数;

}

`

带pcke的授权码验证方式:

`

使用系统;

使用系统。集合。通用;

使用识别模型.客户;

使用微软。安全;

使用欧文

利用陈谦。应用。组织;

使用系统。配置;

使用系统Linq .

使用系统. Net。超文本传送协议(Hyper Text Transport Protocol的缩写)

使用系统。安全。密码学;

使用系统。文字;

使用系统。网络助手;

使用识别模型

使用微软。识别模型。协议;

使用微软哦.

使用微软。奥因。安全。饼干;

使用微软。安全通知;

使用微软哦。保安。OpenIdConnect

使用系统。安全。索赔;

使用微软身份模型。协议。openidconnect

命名空间列侬。应用程序。授权

>
{
public static class LennonAuthExtension
{
private static string OIDC_ClientId = ConfigurationManager.AppSettings["oidc:ClientId"];
private static string OIDC_ClientSecret = ConfigurationManager.AppSettings["oidc:ClientSecret"];
private static string OIDC_Authority = ConfigurationManager.AppSettings["oidc:Authority"];
private static string OIDC_RedirectUri = ConfigurationManager.AppSettings["oidc:RedirectUri"];
private static string OIDC_PostLogoutRedirectUri = ConfigurationManager.AppSettings["oidc:PostLogoutRedirectUri"];
private static string OIDC_ResponseType = ConfigurationManager.AppSettings["oidc:ResponseType"];
private static string OIDC_RequireHttpsMeta = ConfigurationManager.AppSettings["oidc:RequireHttpsMeta"];
private static string OIDC_Scope = ConfigurationManager.AppSettings["oidc:Scope"];

    private static string OIDC_RequestTokenUrl = ConfigurationManager.AppSettings["oidc:Authority"] + "/connect/token";
    private static string OIDC_RequestUserinfoUrl = ConfigurationManager.AppSettings["oidc:Authority"] + "/connect/userinfo";
    private static string APPID = ConfigurationManager.AppSettings["APPID"];
    private static IdentityUserBLL identity = new IdentityUserBLL();
    private static UserIBLL userBLL = new UserBLL();
    /// summary
    /// 用于保存数据
    /// 只能读取一次,读取即删除
    /// /summary
    private static Dictionarystring, string UserAuthenticationDic = new Dictionarystring, string();
    /// summary
    /// 只能读取一次,读取即删除
    /// /summary
    /// param name="key"/param
    /// returns/returns
    private static string GetAuthenticationValue(string key)
    {
        if (UserAuthenticationDic.ContainsKey(key))
        {
            var val = UserAuthenticationDic[key];
            UserAuthenticationDic.Remove(key);
            return val;
        }
        else
        {
            return null;
        }
    }
    /// summary
    /// 保存登录过程中的key
    /// /summary
    /// param name="key"/param
    /// param name="value"/param
    private static void SetAuthenticationValue(string key, string value)
    {
        if (UserAuthenticationDic.ContainsKey(key))
        {
            UserAuthenticationDic.Remove(key);
        }
        UserAuthenticationDic.Add(key, value);
    }
    private static void RememberCodeVerifier(RedirectToIdentityProviderNotificationOpenIdConnectMessage, OpenIdConnectAuthenticationOptions n, string codeVerifier)
    {
        var properties = new AuthenticationProperties();
        properties.Dictionary.Add("cv", codeVerifier);
        string key = GetCodeVerifierKey(n.ProtocolMessage.State);
        string value = Convert.ToBase64String(Encoding.UTF8.GetBytes(n.Options.StateDataFormat.Protect(properties)));
        SetAuthenticationValue(key, value);
        n.Options.CookieManager.AppendResponseCookie(
            n.OwinContext,
            key,
            value,
            new CookieOptions
            {
                //SameSite = SameSiteMode.None,
                HttpOnly = true,
                Secure = n.Request.IsSecure,
                Expires = DateTime.UtcNow + n.Options.ProtocolValidator.NonceLifetime
            });
    }
    private static string RetrieveCodeVerifier(AuthorizationCodeReceivedNotification n)
    {
        string key = GetCodeVerifierKey(n.ProtocolMessage.State);
        string codeVerifier = GetAuthenticationValue(key);
        string codeVerifierCookie = n.Options.CookieManager.GetRequestCookie(n.OwinContext, key);
        if (codeVerifierCookie != null)
        {
            var cookieOptions = new CookieOptions
            {
                //SameSite = SameSiteMode.None,
                HttpOnly = true,
                Secure = n.Request.IsSecure
            };
            n.Options.CookieManager.DeleteCookie(n.OwinContext, key, cookieOptions);
            var cookieProperties = n.Options.StateDataFormat.Unprotect(Encoding.UTF8.GetString(Convert.FromBase64String(codeVerifierCookie)));
            cookieProperties.Dictionary.TryGetValue("cv", out codeVerifier);
        }
        return codeVerifier;
    }
    private static string GetCodeVerifierKey(string state)
    {
        using (var hash = SHA256.Create())
        {
            return OpenIdConnectAuthenticationDefaults.CookiePrefix + "cv." + Convert.ToBase64String(hash.ComputeHash(Encoding.UTF8.GetBytes(state)));
        }
    }
    public static void UseGMDIAuthentication(this IAppBuilder app)
    {
        AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            AuthenticationType = "Cookies",
        });
        //默认不需要Https
        bool requireHttpMeta;
        if (!bool.TryParse(OIDC_RequireHttpsMeta, out requireHttpMeta))
        {
            requireHttpMeta = false;
        }
        app.UseOpenIdConnectAuthentication(new Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions
        {
            SignInAsAuthenticationType = Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationDefaults.AuthenticationType,
            Authority = OIDC_Authority, // 建议通过配置文件读取            
            ClientId = OIDC_ClientId, // 向单点登录服务注册时分配的客户端 Id
            ClientSecret = OIDC_ClientSecret,
            RedirectUri = OIDC_RedirectUri, // 回调地址
            PostLogoutRedirectUri = OIDC_PostLogoutRedirectUri,
            ResponseType = OIDC_ResponseType,
            Scope = OIDC_Scope, // 根据实际要请求的资源服务API设置,如果不需要请求其它资源服务API则保持不变
            RequireHttpsMetadata = requireHttpMeta,
            UsePkce = true,
            UseTokenLifetime = false,
            //RedeemCode = true,
            //SaveTokens = true,
            Notifications = new Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications
            {
                RedirectToIdentityProvider = async n =
                {
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
                    {
                        // generate code verifier and code challenge
                        var codeVerifier = CryptoRandom.CreateUniqueId(32);
                        string codeChallenge;
                        using (var sha256 = SHA256.Create())
                        {
                            var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                            codeChallenge = Base64Url.Encode(challengeBytes);
                        }
                        // set code_challenge parameter on authorization request
                        n.ProtocolMessage.SetParameter("code_challenge", codeChallenge);
                        n.ProtocolMessage.SetParameter("code_challenge_method", "S256");
                        RememberCodeVerifier(n, codeVerifier);
                    }
                },
                AuthorizationCodeReceived = async context =
                {
                    var client = new HttpClient();
                    //var disco = await client.GetDiscoveryDocumentAsync(OIDC_Authority);
                    //if (disco.IsError)
                    //    throw new Exception(disco.Error);
                    var codeVerifier = RetrieveCodeVerifier(context);
                    // attach code_verifier on token request
                    //context.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier);
                    var req = new AuthorizationCodeTokenRequest
                    {
                        Address = OIDC_RequestTokenUrl,//disco.TokenEndpoint
                        ClientId = OIDC_ClientId,
                        ClientSecret = OIDC_ClientSecret,
                        Code = context.Code,
                        RedirectUri = OIDC_RedirectUri,
                        // optional PKCE parameter
                        CodeVerifier = codeVerifier
                    };
                    var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(req);
                    if (tokenResponse != null  !tokenResponse.IsError)
                    {
                        var userreq = new UserInfoRequest
                        {
                            Address = OIDC_RequestUserinfoUrl,//disco.UserInfoEndpoint
                            Token = tokenResponse.AccessToken
                        };
                        var userInfoResponse = await client.GetUserInfoAsync(userreq);
                        if (userInfoResponse.IsError)
                            throw new Exception(userInfoResponse.Error);
                        // create a new identity using the claims from the user info endpoint (including tokens)
                        var claims = userInfoResponse.Claims;
                        var account = claims.FirstOrDefault(x = x.Type == "preferred_username");
                        if (account != null)
                        {
                            var loginAccount = account.Value;
                        }
                        var authuser = GetAuthUser(claims);
                        //先检查是否存在,再保存
                        SaveUser(authuser);
                        //然后模拟登录
                        AutoLogin(authuser);
                        #region 使用页面也登录
                        var id = new ClaimsIdentity(OIDC_ResponseType);
                        id.AddClaims(userInfoResponse.Claims);
                        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                        id.AddClaim(new Claim("id_token", tokenResponse.IdentityToken));
                        //id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
                        id.AddClaim(new Claim("email", authuser.email));
                        id.AddClaim(new Claim("preferred_username", authuser.preferredusername));
                        id.AddClaim(new Claim("sub", authuser.preferredusername));
                        id.AddClaim(new Claim("name", authuser.name));
                        context.AuthenticationTicket = new AuthenticationTicket(new ClaimsIdentity(id.Claims, AuthenticationTypes.Password, "name", "role"),
                            new AuthenticationProperties { IsPersistent = true }); 
                        #endregion
                    }
                },
            }
        });
    }
    private static void AutoLoginQC(AuthUserQCModel authUser)
    {
        if (authUser == null) return;
        //本地模拟登录
    }
    private static void AutoLogin(AuthUserModel authUser)
    {
        if (authUser == null) return;
        OperatorHelper.Instance.AddLoginUser(authUser.sub, APPID, null);
        var userInfo = new UserInfo();
        var loginAccount = authUser.name;
        identity.IdentityLogin(ref userInfo, ref loginAccount);
    }
    public static void SaveUser(AuthUserModel authUser)
    {
    }
    public static AuthUserModel GetAuthUser(IEnumerableClaim claims)
    {
        AuthUserModel user = null;
        if (claims != null)
        {
            user = new AuthUserModel();
            user.sub = getClaimsValue(claims, "sub");
            user.name = getClaimsValue(claims, "name");
            user.given_name = getClaimsValue(claims, "given_name");
            user.departmentId = getClaimsValue(claims, "departmentId");
            user.departmentName = getClaimsValue(claims, "departmentName");
            user.email = getClaimsValue(claims, "email");
            user.post = getClaimsValue(claims, "post");
            user.rank = getClaimsValue(claims, "rank");
            user.officeType = getClaimsValue(claims, "officeType");
        }
        return user;
    }
    public static AuthUserQCModel GetQCAuthUser(IEnumerableClaim claims)
    {
        AuthUserQCModel user = null;
        if (claims != null)
        {
            user = new AuthUserQCModel();
            user.preferredusername = getClaimsValue(claims, "preferred_username");
            user.name = getClaimsValue(claims, "name");
            user.nickname = getClaimsValue(claims, "nickname");
            user.gender = getClaimsValue(claims, "gender");
            user.phonenumber = getClaimsValue(claims, "phonenumber");
            user.email = getClaimsValue(claims, "email");
        }
        return user;
    }
    public static string getClaimsValue(IEnumerableClaim claims, string key)
    {
        if (claims != null  !string.IsNullOrEmpty(key))
        {
            var claim = claims.FirstOrDefault(x = x.Type.Equals(key, StringComparison.OrdinalIgnoreCase));
            if (claim != null)
            {
                return claim.Value;
            }
        }
        return "";
    }
}
public class AuthUserQCModel
{
    /// summary
    /// sub
    /// /summary
    public string preferredusername { get; set; }
    /// summary
    /// 工号
    /// /summary
    public string name { get; set; }
    /// summary
    /// 姓名
    /// /summary
    public string nickname { get; set; }
    /// summary
    /// 性别
    /// /summary
    public string gender { get; set; }
    /// summary
    /// 邮箱
    /// /summary
    public string email { get; set; }
    /// summary
    /// 职位
    /// /summary
    public string phonenumber { get; set; }
}

}

`

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/112076.html

(0)

相关推荐

  • 抖音刷粉神器电脑版-抖音刷1w赞多少费用

    技术抖音刷粉神器电脑版-抖音刷1w赞多少费用抖音刷粉神器电脑版-抖音刷1w赞多少费用
    第二:虽然最起初是15秒的视频,但还是需要用心去制作和拍摄视频的。
    免费刷颤音粉丝代刷网
    宣传。这里就不多说了,你在这里看到这篇文章,

    测评 2021年11月13日
  • mybatis中返回值应该配置什么(mybatis中select方法怎么写)

    技术Mybatis Select Count(*)的返回值类型是什么本篇内容介绍了“Mybatis Select Count(*)的返回值类型是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就

    攻略 2021年12月21日
  • nginx如何处理request body参数配置

    技术nginx如何处理request body参数配置这篇文章主要介绍nginx如何处理request body参数配置,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!通常情况下,nginx与客户端

    攻略 2021年11月21日
  • 出租车起步价多少公里,出租车的起步价是什么意思

    技术出租车起步价多少公里,出租车的起步价是什么意思打底起步价出租车起步价多少公里:指的是打车的一个基础价格,意思是上车后不管你走多远,哪怕100米都要给的这个价钱。
    全国部分城市出租车起步价:
    北京
    起步价:白天10元/

    生活 2021年10月25日
  • 理解Java的接口和抽象类

    技术理解Java的接口和抽象类 理解Java的接口和抽象类深入理解Java的接口和抽象类对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两

    礼包 2021年12月23日
  • ORACLE中出现ORA-28365错误怎么办

    技术ORACLE中出现ORA-28365错误怎么办这篇文章主要为大家展示了“ORACLE中出现ORA-28365错误怎么办”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“ORA

    攻略 2021年11月20日