zoukankan      html  css  js  c++  java
  • 单点登录SSO

    一、概述

    单点登录,全称为Single Sign On,在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它是一个解决方案,目的是为了整合企业内多个应用系统,仅由一组账号只需进行一次登录,就可被授权访问多个应用系统。主要涉及到包括单点登录与单点注销两部分。

    1、单点登录

    sso需要一个独立的认证中心,认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权,间接授权通过令牌实现。sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话。

    1. 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

    2. sso认证中心发现用户未登录,将用户引导至登录页面

    3. 用户输入用户名密码提交登录申请

    4. sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌

    5. sso认证中心带着令牌跳转会最初的请求地址(系统1)

    6. 系统1拿到令牌,去sso认证中心校验令牌是否有效

    7. sso认证中心校验令牌,返回有效,注册系统1

    8. 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源

    9. 用户访问系统2的受保护资源

    10. 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

    11. sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌

    12. 系统2拿到令牌,去sso认证中心校验令牌是否有效

    13. sso认证中心校验令牌,返回有效,注册系统2

    14. 系统2使用该令牌创建与用户的局部会话,返回受保护资源

    2、单点注销

    在一个子系统中注销,所有子系统的会话都将被销毁

    sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作

    1. 用户向系统1发起注销请求

    2. 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求

    3. sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址

    4. sso认证中心向所有注册系统发起注销请求

    5. 各注册系统接收sso认证中心的注销请求,销毁局部会话

    6. sso认证中心引导用户至登录页面

    二、示例

    本示例采用基于cookie的认证方式。

    1、新建项目

    2、新建AES加密帮助类

    using Microsoft.AspNetCore.DataProtection;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SSOServer.Helper
    {
        public static class AESHelper
        {
            private static readonly byte[] SaltBytes = { 13, 34, 27, 67, 189, 255, 104, 219, 122 };
    
            public static byte[] Encrypt(byte[] bytesToBeEncrypted, string key)
            {
                return Excute(bytesToBeEncrypted, key, OpType.Encrypt);
            }
    
            public static byte[] Decrypt(byte[] bytesToBeDecrypted, string key)
            {
                return Excute(bytesToBeDecrypted, key, OpType.Decrypt);
            }
    
            private static byte[] Excute(byte[] inputBytes, string key, OpType opType)
            {
                byte[] outputBytes;
    
                byte[] passwordBytes = Encoding.UTF8.GetBytes(key);
    
                passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
    
                using (var ms = new MemoryStream())
                {
                    using (var aes = new RijndaelManaged())
                    {
                        SetAesOption(aes, passwordBytes);
    
                        using (var cs = new CryptoStream(ms, CreateCryptoTransform(opType, aes), CryptoStreamMode.Write))
                        {
                            cs.Write(inputBytes, 0, inputBytes.Length);
                        }
    
                        outputBytes = ms.ToArray();
                    }
                }
    
                return outputBytes;
            }
    
            private static void SetAesOption(RijndaelManaged aes, byte[] passwordBytes)
            {
                aes.KeySize = 256;
                aes.BlockSize = 128;
    
                var keyByte = new Rfc2898DeriveBytes(passwordBytes, SaltBytes, 1000);
                aes.Key = keyByte.GetBytes(32);
                aes.IV = keyByte.GetBytes(16);
    
                aes.Mode = CipherMode.CBC;
            }
    
            private static ICryptoTransform CreateCryptoTransform(OpType opType, RijndaelManaged rijndaelManaged)
            {
                switch (opType)
                {
                    case OpType.Decrypt:
                        return rijndaelManaged.CreateDecryptor();
                    case OpType.Encrypt:
                        return rijndaelManaged.CreateEncryptor();
                    default: throw new Exception("enkonw type");
                }
            }
    
        }
    
        internal enum OpType
        {
            Decrypt,
            Encrypt
        }
    
        internal class AesDataProtector : IDataProtector
        {
            private const string Key = "!@#$%123";
    
            public IDataProtector CreateProtector(string purpose)
            {
                return this;
            }
    
            public byte[] Protect(byte[] plaintext)
            {
                return AESHelper.Encrypt(plaintext, Key);
            }
    
            public byte[] Unprotect(byte[] protectedData)
            {
                return AESHelper.Decrypt(protectedData, Key);
            }
        }
    }

    3、Startup.cs中注入Cookie服务

  • 相关阅读:
    git学习记录——基础概念和文件的基本操作
    java 之 Properties 类
    java 之 Map类
    java 之 迭代器
    java 之 Collection类
    java 之日期时间操作
    java 之String类
    如何把ASP.NET MVC项目部署到本地IIS上
    [工具]Visual Studio
    [MVC][Shopping]Copy Will's Code
  • 原文地址:https://www.cnblogs.com/qtiger/p/14894642.html
Copyright © 2011-2022 走看看