tnblog
首页
视频
资源
登录

NET Core【IdentityServer4单点登录】+【退出登录】

11601人阅读 2019/12/19 10:07 总访问:98794 评论:0 收藏:1 手机
分类: .NET Core

第一天接触NetCore,感觉坑很多,其他都还良好



    比如说我们现在有三个系统,一个是商品系统,一个是订单系统,另外一个就是单独的登录系统,

    当我们要访问商品系统或者订单系统的时候,我们首先得判断一下我们的本地客户端是否有登录缓存,

    如果没有的话就会再到统一的认证中心去找,如果还是没有,就会自动跳转到登录页面,登录成功后,

    我们要访问订单系统或者商品系统时,就直接在自己本地客户端取出登录缓存即可,

    但是得做一下相关的操作,在订单和商品服务的StartUp.cs里面都要添加一下服务记录登录状态


   
   services.AddAuthentication(options =>  
   {
          options.DefaultScheme = "Cookies";
          options.DefaultChallengeScheme = "oidc";
      })
          .AddCookie("Cookies")
           .AddOpenIdConnect("oidc", options =>
            {
                  options.SignInScheme = "Cookies";
                  options.Authority = "http://localhost:56772"; //登陆中心的地址
                  options.RequireHttpsMetadata = false;
                  options.ClientId = ".net58_Order";
                  options.SaveTokens = true;
             });

   

 以及添加身份验证和session中间件

 //身份验证
 app.UseAuthentication();
  //启用session中间件
  app.UseSession();

这几样都是必不可少的,另外我们还得在登录系统里面加一个Config.cs类

public class Config
    {
        // scopes define the resources in your system
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };
        }
        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                // OpenID Connect隐式流客户端(MVC)
                new Client
                {
                    ClientId = ".net58_Order", //订单系统
                    ClientName = "MVC Client",
                    AllowedGrantTypes = GrantTypes.Implicit,//隐式方式
                    RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false                      
                    RedirectUris = { "http://localhost:56574/signin-oidc" },//登录成功后返回的订单系统客户端地址
                    //PostLogoutRedirectUris = { "http://localhost:56574/signout-callback-oidc" },//注销登录后返回的客户端地址
                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile
                    }
                },
                 new Client
                {
                    ClientId = ".net58_product", //商品系统
                    ClientName = "MVC Client",
                    AllowedGrantTypes = GrantTypes.Implicit,//隐式方式
                    RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false                      
                    RedirectUris = { "http://localhost:55447/signin-oidc" },//登录成功后返回的商品系统客户端地址
                    //PostLogoutRedirectUris = { "http://localhost:55447/signout-callback-oidc" },//注销登录后返回的客户端地址
                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile
                    }
                }
            };
        }
    }


一定要记得在订单和商品属性[Authorize]置于整个Controller之上。当用户有操作时,进入控制器前都会先验证用户是否登录,或者存储用户信息过期从而返回登录界面。


   [Authorize]

  

//查询用户名和密码

public class UserDAL : IUserDAL
    {
        private readonly MyContext myContext;
        
        //构造函数注入
        public UserDAL(MyContext myContext2)
        {
            myContext = myContext2;
        }
        public Users Login(string UserName, string Userpwd)
        {
            Users users = myContext.Users.Where(a => a.UserName == UserName && a.UserPwd == Userpwd).FirstOrDefault();
            return users;
        }
        //异步
        public Task<Users> LoginAsync(string UserName, string Userpwd)
        {
            Task.Run(() =>
                { 
                Users users = myContext.Users.Where(a => a.UserName == UserName && a.UserPwd == Userpwd).FirstOrDefault();
                return users;
             });
            return null;
        }
    }


IUserDAL接口

namespace LoginSystem.DAL.Interface
{
    public interface IUserDAL
    {
        Users Login(string UserName, string Userpwd);
        Task<Users> LoginAsync(string UserName, string Userpwd);
    }
}


在登录系统的StartUp.cs类里面的这个ConfigureServices方法里面添加点配置


   //配置依赖注入关系
    services.AddTransient<IUserDAL, UserDAL>();

      services.AddDbContext<MyContext>(option => {
      
       option.UseSqlServer("Data Source =.; Initial Catalog =My; User ID = sa; Password = 123456");
       
     });
             
  services.AddIdentityServer()//Ids4服务
  .AddDeveloperSigningCredential()//添加开发人员签名凭据
  .AddInMemoryIdentityResources(Config.GetIdentityResources()) //添加内存apiresource
  .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置资源放到内存


另外在登录系统里面启用一下id这个服务,这个服务也需要我们自己下载,版本根据个人需求下就可以啦

下载包:install-package identityServer4 -version 2.1.1
  //启用id4
  app.UseIdentityServer();


再来说一下关于登录系统里面的登录,

NetCore里面是没有Session,我们要使用的话,得自己下载一下,需要哪种版本根据自己需求下

下载包:Install-package Microsoft.AspNetCore.Session -Version 2.1.1
 public class AccountController : Controller
    {
        /// <summary>
        /// 登录页面
        /// </summary>
        [HttpGet]
        public IActionResult Login(string returnUrl = null)
        {
            ViewData["returnUrl"] = returnUrl;
            return View();
        }
        
        
        //依赖注入
        private readonly IIdentityServerInteractionService _interaction;
        private readonly IUserDAL _userDAL;
        public AccountController(IIdentityServerInteractionService interaction, IUserDAL userDAL )
        {
            _interaction = interaction;
            _userDAL = userDAL;
        }
        
        //内部跳转
        private IActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                //如果是本地
                return Redirect(returnUrl);
            }
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }
        /// <summary>
        /// 登录post回发处理
        /// </summary>
        [HttpPost]
        public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)
        {
            ViewData["returnUrl"] = returnUrl;
            
            Users users =  _userDAL.Login(userName, password);
            
            //判断是否为空
            if (users != null)
            {
                AuthenticationProperties props = new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1)),
                };
                //注意这里应该引用Microsoft.AspNetCore.Http这个下面的
                await HttpContext.SignInAsync("2123", userName, props);
                //HttpContext.SignOutAsync();
                if (returnUrl != null)
                {
                    return RedirectToLocal(returnUrl);//登陆成功跳转原地址
                    //return Redirect("http://localhost:44396/home/index");
                }
                return View();
            }
            else
            {
                return Content("登录失败");
            }
         }
        }


登录页面的代码

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Login</title>
    <script>
        new Oidc.UserManager().signinRedirectCallback().then(function (user) {
            alert("登录成功后跳转");
            alert(user.state);
            window.location = user.state;
        }).catch(function (e) {
            console.error(e);
        });
    </script>
</head>
<body>
    <div align="center">
        <h1>登录认证中心</h1>
        <form method="post" action="/Account/Login">
            用户名:<input type="text" name="userName" /><br />
            密  码:<input type="password" name="password" />
            <input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" /> <br />
            <input type="submit" value="登录" />
        </form>
    </div>
</body>
</html>

如果没有登录,订单系统和商品系统都会自动跳转回到登录界面



登录成功后的订单页面和商品页面


再来说一下退出登录


首先在商品系统的index.cshtml页面,写一个退出登录的a标签事件

<a href="/account/Logout" style="float:right;color:#ff0000;font-size:30px">退出登录</a>


接下来就是在登录系统里边写相关操作

 //退出登录
        private readonly IIdentityServerInteractionService _interaction;
        public AccountController(IIdentityServerInteractionService interaction)
        {
            _interaction = interaction;
        }
        [HttpGet]
        public async Task<IActionResult> Logout(string logoutId)
        {
            #region IdentityServer4 退出登录后,默认会跳转到Config.Client配置的PostLogoutRedirectUris地址,
            //做如下改动,则会动态的跳转到原来的地址
            var logout = await _interaction.GetLogoutContextAsync(logoutId);
            await HttpContext.SignOutAsync();
            if (logout.PostLogoutRedirectUri != null)
            {
                return Redirect(logout.PostLogoutRedirectUri);
            }
            var refererUrl = Request.Headers["Referer"].ToString();
            return Redirect(refererUrl);
            #endregion
        }


再到Home控制器里边向IdentityServer进行往返,目的清除单点登录会话

public IActionResult Logout()
 {
    return SignOut("Cookies", "oidc");
  }

步骤有点多,会被绕晕,得慢慢来,特别是那些地址,千万不能填错,坑也很多,得踩过之后才知道!


评价
人之因此能,是坚信能
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
欢迎加群交流技术