SSO 单点登录_sso登陆

SSO 单点登录_sso登陆单点登录(SingleSignOn),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。实现SSO的主要工具是Cookie

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。实现 SSO 的主要工具是 Cookie

实现步骤

SSO_Step

简的来说:申请票据、存储票据、查验票据。

同域 SSO 登录

同域SSO

此处使用 struts2 作为 MVC 框架,可根据实际需要替换

登录界面

接收用户登录信息

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, inital-scale=1">
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <center>
        <h1>请登录</h1>
        <form action="/sso/doLogin.action" method="post">
            <span>用户名:</span><input type="text" name="username">
            <span>密码&nbsp;&nbsp;:</span><input type="password" name="password"><br>
            <%-- gotoUrl 包含从其它页面过来的地址,登录完毕后跳转回 gotoUrl --%>
            <input type="hidden" name="gotoUrl" value="${gotoUrl}">
            <input type="submit">
        </form>
    </center>
</body>
</html>

Jetbrains全家桶1年46,售后保障稳定

处理用户登录信息

import com.opensymphony.xwork2.ActionSupport;
import lee.sso.util.SSOCheck;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

public class SSOAction extends ActionSupport { 
   

    private String username;
    private String password;
    private String gotoUrl;

    public String doLogin() {
        /* 此处不进行数据用户数据验证, 只关注 sso */
        boolean ok = SSOCheck.checkLogin(username, password);
        if (ok) {
            /* 此处 cookie 值应为加密后的值,此处亦省去 */
            Cookie cookie = new Cookie("ssocookie", "sso");
            cookie.setPath("/");
            HttpServletResponse response = ServletActionContext.getResponse();
            response.addCookie(cookie);
            return SUCCESS;
        }
        // 失败此处不做处理,或者返回登录页面
        return null;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGotoUrl() {
        return gotoUrl;
    }

    public void setGotoUrl(String gotoUrl) {
        this.gotoUrl = gotoUrl;
    }
}

处理登录信息工具类

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

public class SSOCheck { 
   
    public static final String USERNAME = "user";
    public static final String PASSWORD = "123";

    public static boolean checkLogin(String username, String password) {
        return username.equals(USERNAME) && password.equals(PASSWORD) ? true
                : false;
    }

    /** * 实际开发时应放在拦截器,此处为了方便 * * @param request * @return */
    public static boolean checkCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("ssocookie") && cookie.getValue()
                        .equals("sso"))
                    return true;
            }
        }
        return false;
    }
}

登录页面的 struts2 配置

<package name="sso" namespace="/sso" extends="struts-default">
        <action name="doLogin" class="lee.sso.action.SSOAction" method="doLogin">
            <result name="success" type="redirect">${gotoUrl}</result>
        </action>
    </package>

编写 domain1

主页,当为用户访问时未登录将先跳转登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, inital-scale=1">
    <meta charset="UTF-8">
    <title>domain1 的标题</title>
</head>
<body>
    <h1>欢迎访问 domain1,这是 domain1 的主页</h1>
</body>
</html>

domain1 Action 类

import com.opensymphony.xwork2.ActionSupport;
import lee.sso.util.SSOCheck;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletRequest;

public class Domain1Action extends ActionSupport { 
   

    private String gotoUrl;

    public String main() {
        HttpServletRequest request = ServletActionContext.getRequest();
        if (SSOCheck.checkCookie(request)) {
            return SUCCESS;
        }
        // 此处声明登录完成后跳转的页面
        gotoUrl = "/domain1/main.action";
        return LOGIN;
    }

    public String getGotoUrl() {
        return gotoUrl;
    }

    public void setGotoUrl(String gotoUrl) {
        this.gotoUrl = gotoUrl;
    }
}

domain1 的 struts2 配置

<package name="domain1" namespace="/domain1" 
             extends="struts-default">
        <action name="main" class="domain1.Domain1Action"
                method="main">
            <result name="success">/domain1.jsp</result>
            <result name="login">/login.jsp</result>
        </action>
    </package>

domain2 与 domain1 区别不大,只需将 1 复制一份,将 1 改为 2 即可。

效果

填写 domain1 (别点提交)

登录 domain1

进入 domain2 看看

domain2

domain1 点解提交

domain1主页

此时刷新 domain2 登录界面

domain2 主页

神奇的一幕发生了,不需要登录信息直接进入 domain2 的主页

这是因为在登录 domain1 后服务器向我们发送了一个 cookie,浏览器保存了。当刷新 domain2 时,浏览器带着未过期的 cookie 给服务器发请求,服务器判断此 cookie 的会话是否还有效,若有,则直接跳过登录页面进入 domain2 主页。

cookie


同父域 SSO 登录

若在同一机器部署测试,可更改文件C:\Windows\System32\drivers\etc\hosts文件

同父域 SSO 登录

由图可看出,同父域的 SSO 登录与同域 SSO 登录并无多大区别,需要解决的问题有两个,一个是 cookie 的跨域问题以及服务器之间的通信。可根据同域 SSO 登录修改代码。

此处主要使用了子域可访问父域cookie的机制。设置 cookie 时,需要我们统一一个 token ,即 cookie 的变量名。

我们访问http://demo1.x.com/demo1/main.action时,查看 request.getCookies()是否包含我们所需的信息,若无,则带着验证后跳转地址<input type="hidden" name="gotoUrl">跳转到统一验证接口http://check.x.com/sso/doLogin.action验证用户名和密码。

统一验证接口返回 cookie 之前,必须设置

// 由 . 开头,则只有子域名可用。若无,则主域名和子域名可用
cookie.setDomain(".x.com");  // 同一父域名
cookie.setPath("/");

浏览器保存cookie后,带着cookie跳转回
http://demo1.x.com/demo1/main.action
要设置setDomain(),否则请求无法携带cookie

服务器之间的通信

http://demo1.x.com/demo1/main.action的服务器接收到cookie时,将cookie名cookie值发给统一验证接口http://check.x.com/sso/checkCookie.action处理,约定好返回值是什么,成功返回后判断是否让其访问资源。

可通过 HttpURLConnection 类或者使用 HttpClient 客户端进行通信。


完全跨域 SSO 登录

即域名完全不同,如www.a.comwww.b.com

完全跨域SSO

登录验证

freecodecampLogin

进入www.a.com资源页面,查看cookie,若无,则跳转登录页面。

www.a.com服务器接收用户信息数据,但不验证,将用户信息数据传输http://www.x.com/sso/doLogin.action验证。

<form action="/doLogin.action"></form>

进入 action 类,根据代码逻辑与验证服务器通信

result = SSOUtil.post(checkSSOUrl, username, password);

验证成功后返回信息给www.a.com,判断可访问资源后并向浏览器发送 cookie 存放确认用户身份的 token(即 cookieValue)

Cookie cookie = new Cookie(cookieName, cookieValue);
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);

问题此cookie只有www.a.com才能访问,所以,需要在确定用户身份后,访问资源页面时向www.b.com发送请求,并让www.b.com向浏览器发送cookie的值

www.a.comwww.b.comaction类里添加方法,传送兄弟 URL 和传参,则无论是访问 a 或 b ,登录成功后在cookie有效期内都能访问 b 或 a 的资源。

List<String> urlList; // 存放兄弟 URL
String cookieName;
String cookieValue;

...
// Struts2 的 OGNL
setter/getter
...

public String main() {
    ...
    urlList.add("www.b.com/demo2/pushCookieToBrowser.action"
        + "?cookieName=" + cookieName
        + "&cookieValue=" + cookieValue);
    ...
}

public void pushCookieToBrowser() {
    HttpServletRequest request = ServletActionContext.getRequest();
    this.cookieName = request.getParameter("cookieName");
    this.cookieValue = request.getParameter("cookieValue");
    Cookie cookie = new Cookie(cookieName, cookieValue);
    HttpServletResponse response = ServletActionContext.getResponse();
    response.addCookie(cookie);
}

在登录成功的资源页面使用 <iframe> 将返回数据信息循环请求发给兄弟服务器域名,让兄弟域名向浏览器发送 cookie,完成跨域 SSO

www.a.com loginSuccess.jsp

<c:forEach var="url" items="${urlList}">
    <%-- 隐藏 iframe --%>
    <iframe src="${url}" width="0px" hight="0px" style="dispaly: none"></iframe>
</c:forEach>

再访问 b 的资源时将不需要再次输入密码。


注意

  1. 核心是Cookie,需要注意设置的域、位置和安全性。
  2. 应用群的安全问题:木桶效应。

资料

慕课视频

单点登录原理与简单实现

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206736.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Springboot + Spring Security + jwt-token实现权限认证

    Springboot + Spring Security + jwt-token实现权限认证

    2021年8月31日
    55
  • 破解不加微信看朋友圈「建议收藏」

    破解不加微信看朋友圈「建议收藏」有网友发邮件问,用空间万能查看器天涯,可以强制看非好友的朋友圈?今天小编就给大家说说微信朋友圈的一些事情。微信好友之间可以看到对方朋友圈每次发的一些动态记录,只要对方不设置让你看不到,就可以看到。不是微信好友想看对方朋友圈,也是可以理解的,毕竟微信朋友圈,和QQ空间设置了这个权限是需要权限才能进去的,有的网友有方法进别人设置了权限的QQ空间,那么微信的权限朋友圈其实和QQ权限空间原理是一样的。QQ空间和微信朋友圈其实是一样的意思,只是表现的形势不同,但是有的人喜欢上微信,有的人喜欢上QQ,不管你

    2022年4月29日
    2.7K
  • LinQ的学习(一)

    LinQ的学习(一)
    LinQ技术有什么用呢?
    LinQ使得开发人员可以象查询数据库一样来查询自己的对象,包括数组,xml,mdf文件等等。而LinQ提供了几乎统一的访问方式。
    例子:
    int[]numbers=newint[7]{0,1,2,3,4,5,6};
               varnumQuery=fromnuminnumberswhere(num%2==0)selectnum;
               

    2022年6月1日
    36
  • RelativeLayout.LayoutParams学习与运用

    RelativeLayout.LayoutParams学习与运用1、了解LayoutParams其实LayoutParams就是代表一个布局属性,每一个ViewGroup对应一种LayoutParams。LinearLayout对应LinearLayout.LayoutParams,RelativeLayout对应RelativeLayout.LayoutParams。我们在XML中写的大多数属性,在代码中通过LayoutParams同样可以操作界面布局。下面以

    2022年7月17日
    16
  • C++面试「建议收藏」

    C++面试「建议收藏」C++面试

    2022年4月22日
    32
  • 更改文字、图片和视频大小(缩放)

    更改文字、图片和视频大小(缩放)

    2022年2月9日
    117

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号