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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java分割String字符串成list

    java分割String字符串成list示例:Stringsn=“1234,567,8910”;List<String>snList=Arrays.asList(sn.split(“,”));

    2022年6月21日
    99
  • ebpf原理分析_HRTEM怎么分析

    ebpf原理分析_HRTEM怎么分析ebpf原理解析

    2022年9月21日
    4
  • 五个步骤教你数据清洗_数据仓库ods层

    五个步骤教你数据清洗_数据仓库ods层关于ODS层是否做数据清洗一直是存在争议的,但有一点是可以确定的,对于比较重的清洗工作是要留到后面数仓的ETL过程中进行处理。但是,有这么一种情况:我们在长期的生产实际过程中,发现部分已知的数据问题的处理可以通过自动化的方式来处理,这种方式通常在数据入库之前,做额外的加工处理后再做入库操作。数据清洗的主要工作是处理那些不符合要求的数据,从而提升数据质量,比如一些常见的问题:错误的数据、重复的数据错误的数据这种错误通常是业务系统处理不够健全造成的,比如字符串数据后面有回车空格、日期格式不正确、日期

    2022年10月5日
    2
  • 用SrvAny.exe封装服务「建议收藏」

    用SrvAny.exe封装服务「建议收藏」用SrvAny.exe封装服务

    2022年5月29日
    54
  • EagleEye_eyekey

    EagleEye_eyekey摘要:EagleEye作为阿里集团老牌的链路跟踪系统,其自身业务虽不在交易链路上,但却监控着全集团的链路状态,特别是在中间件的远程调用上,覆盖了集团绝大部分的场景,在问题排查和定位上发挥着巨大的作用,保障了各个系统的稳定性,为整个技术团队打赢这场战役保驾护航。作者:王华锋(水彧)背景 双十一一直是阿里巴巴集团每年要打的一场大战役。要打赢这场战役,技术上,不仅仅是几个应用、几个

    2022年4月19日
    64
  • 阿里笔试题目「建议收藏」

    阿里笔试题目「建议收藏」题目描述一个淘宝的订单中包含n(10&gt;=n&gt;=1)种商品A1,A2,…,An,每种商品数量分别为a1,a2,…,an个,记做{a1,a2,…,an}(ak&gt;0)。订单在仓库生产过程中,仓库为了提升作业效率,会提前对热门组合商品进行预包装。假设这n个商品有m(9&gt;=m&gt;=1)个商品组合,每个组合bomk包含A1,A2,…,An的数量分别为{b1,b2,…,bn}(bk&…

    2022年5月10日
    39

发表回复

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

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