.net core 3.1 单点登陆(附源码)

我这里是用JWT机制、IdentityServer4、Cookie来做单点登陆的,由于cookie本身的局限性,目前只能在同域名下单点登陆,如果有想做不同域名的可以访问我的上一篇,即登陆后在Headers中携带Authorization:Bearer Token密钥进行登陆。

以登录cookie为例说明


1,共享之间的二级域名必须是解析于同一个顶级域名之下;

2,比如现在有两个二级域名,a.xxx.com(域名A)和b.xxx.com(域名B)。两个都解析于域名xxx.com
顶级域名之下。

3,现在域名A的登录cookie域名B下面需要使用。

4,域名A的登录cookie把cookie域设置成xxx.com(注意不要写成www.xxx.com,因为www.xxx.com
也属于二级域名,不是顶级域名),path设置成’/’

5,此时域名B下面可以读取域名A写入的cookie

6,这样就可以实现域名A的cookie被域名B共享

7,如果要实现相互共享,就把两个域名的cookie域都设置成xxx.com

有了这种思路我们就可以在项目中来设置相应属性来实现了。

主要登陆代码如下:

        /// <summary>
        /// SSO单点登陆 jwt写入cookie数据
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <param name="redirectUrl"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult WriteInToken(User user1)
        {
            if (user1.userName == "admin" || user1.userName == "张三" &&
 user1.passWord == "123456") //实际数据库校验
            {
                //string name = this.UserContext.User.UserName;
                User user = new User()
                {
                    userId = 1000,
                    account = user1.userName,
                    userName = user1.userName,
                    age = 18,
                    email = "zhangsan@qq.com"
                };
                string token = new JWTService().GetJwtToken(user);

                CookieOptions cookieOptions = new CookieOptions();
                cookieOptions.Domain = "openwebsite.cn"; //设置domain让cookie共享
                cookieOptions.Path = "/";
                cookieOptions.HttpOnly = true;
              
                HttpContext.Response.Cookies.Append("openwebsite", token, cookieOptions);


                ////把token写入cookie
                //Response.Cookies.Append("openwebsite", token);


           
                //登录成功跳转到对应系统
                user1.redirectUrl += $"https://jwttwo.openwebsite.cn/?Authorization={token}";
                // return Redirect(user1.redirectUrl);
                //return RedirectToAction("LoginYZ", "Home");
                return Json(token);
            }
            else
            {
                //登录失败
                return Json("登录失败");
            }
        }

这里就设置了cookie作用域以及cookie的名称、数据。同时还设置了JWT的有效期等。

Star­tup启动文件设置:

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
  
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddMvc(option =>
            {
                //登陆过滤器
                option.Filters.Add(new ApiAuthorizationFilter());
                //option.Filters.Add(new ApiResultFilter());
                //option.Filters.Add(new BusinessLogicExceptionFilter());

            });


            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                  .AddJwtBearer(options =>
                  {
                      var serverSecret = new SymmetricSecurityKey(Encoding.UTF8.
                          GetBytes(Configuration["Jwt:Secret"]));
                      options.TokenValidationParameters = new
                          TokenValidationParameters
                      {
                          ValidateIssuer = false,//是否验证Issuer
                          ValidIssuer = Configuration["Jwt:Issuer"],
                          ValidateAudience = true,//是否验证Audience
                          ValidAudience = Configuration["Jwt:Audience"],
                          ValidateLifetime = true,//是否验证失效时间
                          ClockSkew = TimeSpan.FromSeconds(5),
                          ValidateIssuerSigningKey = true,//是否验证SecurityKey
                          IssuerSigningKey = serverSecret
                      };

                      options.Events = new JwtBearerEvents()
                      {
                          //首次收到协议消息时调用。
                          OnMessageReceived = context =>
                          {
                              //携带Authorization
                              //string token = context.Request.Query["Authorization"];
                              //if (!string.IsNullOrEmpty(token))
                              //{
                              //   string jmtoken = DecodeJwt.decode(token);
                              //    JWT wT = JsonConvert.DeserializeObject<JWT>(jmtoken);

                              //    DateTime dtStart = JWTService.StampToDateTime(wT.exp);
                              //    if (dtStart >= DateTime.Now)
                              //    {
                              //        context.Token = token;
                              //    }
                              //}

                        //获取cookie  单点登陆则获取cookie
                              context.Token = context.Request.Cookies["openwebsite"];

                        //获取headers中携带的Authorization   非单点登陆咋取headers中携带的数据
                              //context.Token = context.Request.Query["Authorization"];
                              return Task.CompletedTask;
                          },
                          //如果在请求处理过程中身份验证失败,则调用
                          OnAuthenticationFailed = context =>
                          {
                              //如果过期,则把<是否过期>添加到,返回头信息中
                      if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                              {
                                  //context.Response.Headers.Add("Token-Expired", "true");
   //自定义自己想要返回的数据结果,我这里要返回的是Json对象,通过引用Newtonsoft.Json库进行转换
                                  var payload = JsonConvert.SerializeObject(new { Code = "402", 
Message = "很抱歉,Token无效或已过期" });
                                  //自定义返回的数据类型
                                  context.Response.ContentType = "application/json";
                                  //自定义返回状态码,默认为401 我这里改成 200
                                  context.Response.StatusCode = StatusCodes.Status200OK;
                                  //输出Json数据结果
                                  context.Response.WriteAsync(payload);
                                  // return Task.FromResult(0);
                              }
                              return Task.CompletedTask;
                          },
                          //在安全令牌已通过验证并生成 ClaimsIdentity 后调用。
                          OnTokenValidated = context =>
                          {
                              return Task.CompletedTask;
                          }          
                      };

                  });

            services.AddControllersWithViews();

       }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Shared/Error");
            }
            app.UseStaticFiles();

            ///添加中间件(Middleware) 启用验证
            app.UseAuthentication();

            //路由
            app.UseRouting();


            app.UseAuthorization();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Login}/{id?}");
            });
            //}
        }
    }

这两块就是主要代码,有需要的可以下载源码自己去研究研究。

为您推荐

发表评论

您的电子邮箱地址不会被公开。