原文在这里: 单点登录系统SSO是如何实现的?

所谓单点登录就是在A系统登录以后,跳转到B系统,此时可以直接访问B系统的资源,而不需要二次登录,目前这种需求已经非常普遍了,那么背后是怎么实现的呢?本文将用一个实际的例子来给大家详细的讲解下。
准备工作
(1)准备3个域名来模拟3个站点,www.site1.com和www.site2.com是业务域,www.usercenter.com是用户中心。一般单点登录系统背后都有一个独立的用户中心。

当然我们不需要真的去万网申请3个域名,只需要修改下本机的host文件即可,修改C:\Windows\System32\drivers\etc,添加以下内容:
127.0.0.1 www.site1.com
127.0.0.1 www.site2.com
127.0.0.1 www.usercenter.com

(2)准备一个nginx,把三个域名都挂上
我们本机启动3个tomcat,端口分别是site1:8081,site2:8082,usercenter:8080,通过nginx统一用标准的80来访问。


server {listen       80;server_name  www.usercenter.com;location / {proxy_set_header Host $host;proxy_set_header X-Real-Ip $remote_addr;proxy_set_header X-Forwarded-For $remote_addr;proxy_pass   http://127.0.0.1:8080;}}server {listen       80;server_name  www.site1.com;location / {proxy_set_header Host $host;proxy_set_header X-Real-Ip $remote_addr;proxy_set_header X-Forwarded-For $remote_addr;proxy_pass   http://127.0.0.1:8081;}}server {listen       80;server_name  www.site2.com;location / {proxy_set_header Host $host;proxy_set_header X-Real-Ip $remote_addr;proxy_set_header X-Forwarded-For $remote_addr;proxy_pass   http://127.0.0.1:8082;}}

现在我们就可以在本机用3个tomcat来模拟3个独立域名的服务器了。
原理分析
(1)浏览器访问site1,site1首先检查请求中是否带有site1的cookie,cookie的值是用户的token。如果有则向用户中心检查token的有效性,如果有效则可以直接访问site1,如果没有或者失效,重定向到用户中心去登录。

(2)浏览器进入用户中心的登录页面,用户输入用户名和密码,登录成功以后,用户中心需要写usercenter域的cookie,cookie的值是随机生成的一个token,然后重定向回到site1,同时把token作为url的参数给回传过去,因为cookie是usercenter域的,不是site1域的,只能通过url参数来传递。

(3)浏览器到了site1,还是首先检查cookie为空,然后需要检查参数中是否有用户中心设置的token参数,如果有,检查参数有限性,拿到用户信息,写site1的cookie,cookie的值是用户中心设置的token。

此时,如果浏览器继续访问site1的页面,会回传site1的cookie,只要去用户中心校验有效性即可。

如果,此时要跳转到site2,site2同样也要做:

(1)浏览器访问site2,site2首先检查请求中是否带有site2的cookie,cookie的值是用户的token。如果有则向用户中心检查token的有效性,如果有效则可以直接访问site2,如果没有或者失效,重定向到用户中心去登录。

(2)浏览器进入用户中心要做登录的时候,此时浏览器是传递了site1登录成功以后用户中心下发的cookie的,因为此时访问的是usercenter域,因此用户中心拿到cookie以后,只需要去校验有效性,校验通过则重定向回site2.

(3)浏览器到了site2,还是首先检查cookie为空,然后需要检查参数中是否有用户中心设置的token参数,如果有,检查参数有效性,拿到用户信息,写site2的cookie,cookie的值是用户中心设置的token。

此时,如果浏览器继续访问site2的页面,会回传site2的cookie,只要去用户中心校验有效性即可。

上面啰啰嗦嗦一大堆,看上去很绕很抽象,一团乱麻,还是来看代码吧,看代码就清爽多了,图就不画了,感觉帮助不大。

代码实现

本文我们用springboot+thymeleaf来实现,springmvc也是一样的道理。
site1访问需要登录的页面的时候:

@GetMapping("/main")public String main(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {//首先从cookie中取token,这里只能取site1的cookie//首次访问肯是空,除非后面登陆成功以后设置过String tk = getFromCookie(request);if(tk != null) {//验证token有效性String username = getFromUserCenter(tk);if(username != null) {model.addAttribute("username", username);return "main";}else {//如果失效,重新登录String url = getFullUrl(request);return "redirect:"+String.format(USER_CENTER_LOGIN_URL, URLEncoder.encode(url, "UTF-8"));}}else {//从参数中取,如果从用户中心跳转回来,会在参数中传递tokentk = getFromParam(request);if(tk != null) {//还是要校验下参数的有效性String username = getFromUserCenter(tk);if(username != null) {//生成自己站点下面的cookieCookie cookie = new Cookie(COOKIE_NAME, tk);cookie.setMaxAge(Integer.MAX_VALUE);response.addCookie(cookie);//进入主页model.addAttribute("username", username);return "main";}else {//说明token已经过期,进入用户中心做登录String url = getFullUrl(request);return "redirect:"+String.format(USER_CENTER_LOGIN_URL, URLEncoder.encode(url, "UTF-8"));}}else {//进入用户中心做登录String url = getFullUrl(request);return "redirect:"+String.format(USER_CENTER_LOGIN_URL, URLEncoder.encode(url, "UTF-8"));}}}

usercenter处理业务域的跳转和做登录:
当各个站定向用户中跳的时候,首先访问这个USER_CENTER_LOGIN_URL:


@GetMapping(value="/login")public String to_login(HttpServletRequest request, Model model)throws Exception {String redir_url = request.getParameter("redir_url");//先看是否存在usercenter下面额cookie//只要有一个站点登录成功过,其他的站点往用户中心跳的时候//都会携带这个cookie,只要有效,就可以不用再次登陆String tk = getFromCookie(request);if(tk == null) {//去登陆model.addAttribute("redir_url", redir_url);return "login";}else {//check是否有效String username = getByToken(tk);if(username == null) {model.addAttribute("redir_url", redir_url);return "login";}else {//如果有效,直接跳回去redir_url = addTokenToUrl(redir_url, tk);return "redirect:"+redir_url;}}}

在用户中心做登录:

@PostMapping(value="/login")public String do_login(LoginUser loginUser, String redirect_url, HttpServletResponse res, Model model)throws Exception {String username = loginUser.getUsername();LoginUser userDB = getFromDB(username);if(userDB == null) {model.addAttribute("errmsg", "用户不存在");model.addAttribute("redir_url", redirect_url);return "login";}String pwdDB = userDB.getPassword();if(!pwdDB.equals(loginUser.getPassword())) {model.addAttribute("errmsg", "密码错误");model.addAttribute("redir_url", redirect_url);return "login";}//存redis,注意要设置有效期String tk = UUID.randomUUID().toString();redis.put(tk, userDB);//生成用户中心的cookieCookie cookie = new Cookie(COOKIE_NAME, tk);cookie.setDomain("www.usercenter.com");cookie.setPath("/");cookie.setMaxAge(Integer.MAX_VALUE);res.addCookie(cookie);//跳转回去redirect_url = addTokenToUrl(redirect_url, tk);return "redirect:"+redirect_url;}

下面是用户中心校验token是否有效,有效就返回用户信息:

 @GetMapping(value="/getByToken")@ResponseBodypublic String getByToken(String token)throws Exception {//这里注意:延长下redis的有效期LoginUser user = redis.get(token);if(user != null) {return user.getUsername();}else {return null;}}

代码其实还是挺简单的,主要的界面截图如下:

(1)浏览器访问http://www.site1.com/index.html,这个是个静态页面,不需要登陆:


this is site1 index<br/>
<input type="button" onclick="visitMain()" value="visit main page" />
<script>
function visitMain(){window.location.href="http://www.site1.com/site1/main";
}
</script>

(2)点击visit main page按钮,访问site1站点下需要登录的页面,此时会重定向到usercenter,完整的url是

http://www.usercenter.com/user_center/login?redir_url=http%3A%2F%2Fwww.site1.com%2Fsite1%2Fmain:

(3)输入用户名和密码做登陆,登录成功,跳转回site1,完整的url:

http://www.site1.com/site1/main?user_center_tk=19d89eb0-b135-492f-a684-2a8fc6f7e859,注意:参数中传递了token:

此时,刷新页面的的话,site1是可以拿到cookie中的token的,只需要去检验token有效性即可。

欢迎你:<span th:text="${username}"></span>,这是site1的主页面<br/>
<input type="button" onclick="goToSite2()" value="go to site2"/>
<script>
function goToSite2(){window.location.href="http://www.site2.com/site2/main";
}
</script>

(4)点击页面上go to site2按钮,会直接进入site2的主界面而不需要做登录,因为site2首先是去用户中心,用户中心会拿到之前设置的cookie,校验通过以后,会跳转回site2,注意看site2的url:

http://www.site2.com/site2/main?user_center_tk=19d89eb0-b135-492f-a684-2a8fc6f7e859:


<span th:text="${username}"></span>,这是site2的主页面<br/>
<input type="button" onclick="goToSite1()" value="go to site1"/>
<script>
function goToSite1(){window.location.href="http://www.site1.com/site1/main";
}
</script>

以上就是整个项目的实现,主要的点在于cookie不能跨域,A站只能设置A站的cookie,也只能读取A站的cookie,明白了这个就ok了。退出的代码就不写了,在site1退出的时候,首先要删除site1的cookie,然后要删除用户中心的redis即可。大家有兴趣可以自己实现下。

完整的代码下载:扫码关注文章开头的公众号看原文

代码仅仅是为了展示整个流程,如果是在实际项目中使用可以在业务域上用拦截器之类的来做。

单点登录系统SSO是如何实现的?相关推荐

  1. java sso单点登录源码_Java单点登录系统 sso源码下载

    这是一个使用Java开发的单点登陆系统(sso). 运行截图 单点登陆介绍 单点登录,这就是我们通常称之为SSO.一般来说,大型系统平台将使用这些东西.它解决了频繁登录和验证的过程,即用户的一次登录被 ...

  2. 单点登录系统(SSO)和Session共享解释

    在企业发展初期,企业使用的系统很少,通常一个或者两个,每个系统都有自己的登录模块,运营人员每天用自己的账号登录,很方便. 但随着企业的发展,用到的系统随之增多,运营人员在操作不同的系统时,需要多次登录 ...

  3. 单点登录系统(SSO)的开发思路

    单点登录系统的类别:       就目前比较流行的应用来看,单点登录系统主要分为三种类型:一种是基于oauth协议的网络令牌(我是这么叫的),一种是基于Web Service或者简单Http协议实现的 ...

  4. 单点登录系统SSO概述 | 单点登录讲解(1)

    本项目主要讲解的是单点登录系统的原理及其实现. 本章主要讲解的是单点登录系统的概述部分. 单点登录 单点登录顾名思义就是从一个系统进行登录操作,就可以访问其他附近的系统.单点登录避免了用户重复的登录过 ...

  5. 单点登录系统(SSO)详细设计说明书

    1.引言 1.1编写目的 为了单点登录系统(SSO系统)的可行性,完整性,并能按照预期的设想实现该系统,特编写需求说明书. 同时,说明书也发挥与策划和设计人员更好地沟通的作用. 1.2背景 a.鉴于集 ...

  6. 09-微服务版单点登陆系统(SSO)实践

    目录 单点登陆系统简介 背景分析 单点登陆系统概述 单点登陆系统解决方案设计 单点登陆系统初步设计 服务设计 工程结构设计 SSO父工程创建及初始化 创建父工程 父工程pom文件初始配置 系统基础服务 ...

  7. 单点登录系统(流程简介)

    一.概述 单点登录系统SSO(Single Sign On)是在多个应用系统中,用户只需要登录一次就可以访问相互信任的其它系统 二.系统简介 流程: 1.用户访问应用一 2.应用一检查用户登录,如果用 ...

  8. codeigniter 禁止ip登录_「开源资讯」baigo SSO v4.0 beta-3 发布,单点登录系统

    来源:https://www.oschina.net/news/117020/baigo-sso-4-beta3-released 简介 baigo SSO 是一款基于 HTTP 协议的单点登录系统, ...

  9. SpringBoot+MyBatis+Redis实现SSO单点登录系统(二)

    SpringBoot+MyBatis+Redis实现SSO单点登录系统(二) 三.代码 配置文件配置数据库,redis等相关的信息. # See http://docs.spring.io/sprin ...

最新文章

  1. PHP配置问题:AppServ安装discuz出错 Fatal error:
  2. 正则表达式从基础到深入实战
  3. 2020 China Collegiate Programming Contest Weihai Site补题部分
  4. wpf 创建附加属性实例
  5. jQuery UI dialog插件出错信息:$(this).dialog is not a function
  6. iframe导致的IE6下https页面安全提示
  7. ElasticStack系列之九 master、data 和 client 节点
  8. java中switch、while、do...while、for
  9. 怎么删除计算机中的服务,小白教你怎么删除系统服务
  10. CentOS 开启端口
  11. PHP操作MongoDB技術總結
  12. QuantumultX 初学者傻瓜教程
  13. 在厉害的圈子里耳濡目染 No.110
  14. 宠物商店mysql数据库设计_宠物商城数据库设计
  15. mysql创建/编辑表时的 ROW_FORMAT = Dynamic 和 Compact 有什么区别
  16. 力扣(392.521)补8.26
  17. 买眼镜踩坑【吐槽一下实体店的坑】
  18. 私域流量有什么特点?
  19. Linux 私房菜速读
  20. 英语这样学最有效------少走弯路的学习方法

热门文章

  1. 提高你工作效率的10条建议
  2. 盘点中国未来最赚钱十大行业
  3. C4D教程基础入门课程
  4. Set集合概述和特点
  5. 使用python下载wallpaper Engine订阅的壁纸/视频
  6. 复现抖音动态3D恐龙算法
  7. 表格打印技巧(超级表格也可以打印哦~)
  8. 三年级开始学编程,STEAM训练要趁早
  9. 中国家用便携式除湿机市场深度研究分析报告
  10. 单开双控_单开双控怎么接线