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. 应用群的安全问题:木桶效应。

资料

慕课视频

单点登录原理与简单实现

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • QThread使用——关于run和movetoThread的区别「建议收藏」

    QThread使用——关于run和movetoThread的区别「建议收藏」QThread使用探讨2010-10-2300:30注意:本文停止更新,请优先考虑 Qt线程基础(QThread、QtConcurrent等)dbzhang8002011.06.18QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用QThread,随便

  • 什么是yuv420(苹果6sp升级13怎么样)

    在YUV420中,一个像素点对应一个Y,一个2X2的小方块对应一个U和V。对于所有YUV420图像,它们的Y值排列是完全相同的,只有Y的图像就是灰度图像。YUV420sp与YUV420p的数据格式区别在于UV排列上的完全不同。420p它是先把U存放完后,再存放V,如下图。而420sp它是UV、UV这样交替存放的。有了上面的理论,我就可以准确的计算出一个YUV420在内存中存放的大小。

  • 机器学习之KNN最邻近分类算法[通俗易懂]

    机器学习之KNN最邻近分类算法[通俗易懂]KNN算法简介KNN(K-NearestNeighbor)最邻近分类算法是数据挖掘分类(classification)技术中最简单的算法之一,其指导思想是”近朱者赤,近墨者黑“,即由你的邻居来推断出你的类别。KNN最邻近分类算法的实现原理:为了判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数…

  • 最小生成树的个数_最小生成树的实际应用

    最小生成树的个数_最小生成树的实际应用给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。设最小生成树的边权之和为 sum,严格次小生成树就是指边权之和大于 sum 的生成树中最小的一个。输入格式第一行包含两个整数 N 和 M。接下来 M 行,每行包含三个整数 x,y,z,表示点 x 和点 y 之前存在一条边,边的权值为 z。输出格式包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)数据范围N≤105,M≤3×105输入样例:5 61 2 11 3 22 4 33 5 4

  • 移动机器人轮式里程计

    移动机器人轮式里程计移动机器人灵魂三问:我在哪?我要去哪里?怎么去?其中,第一问对应机器人定位问题。定位问题可阐述为:移动机器人根据自身状态、传感器信息实时确定自己在世界(全局或局部)中的位置与姿态。阿克曼转向的无人驾驶汽车的定位方案主要有:轮式里程计、视觉里程计、激光里程计、惯性导航模块(IMU+GPS)以及多传感器融合。轮式里程计是一种最简单,获取成本最低的方法。与其它定位方案一样,轮式里程计也需要传感器感知外部信息,只不过,轮式里程计采用的电机转速测量模块是一种成本非常低廉的传感器。本文对搭建智能小车系统过程.

  • Java面试之SQL

    Java面试之SQLJava面试之SQL

发表回复

您的电子邮箱地址不会被公开。

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