SpringBoot如何实现同域SSO(单点登录)

单点登录,其实看起来不是很复杂,只是细节上的处理,单点区分有三种

  • 同域SSO
  • 同父域SSO
  • 跨域的SSO

如何实现同域SSO?

个人理解:当用户登录访问demo1.lzmvlog.top时,同时具有访问demo2.lzmvlog.top的能力,即认证完成一次,可以访问所有系统。

实现方式:可以采用Cookie实现,即用户在访问一个系统时,携带认证颁发的信息,系统响应是否具有访问资格,否则跳转认证,也可以采用Session,即Session共享,校验访问用户是否具有有效的信息,提供访问资格

代码实现

依赖

<!--spring-data-jpa-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

配置

server:
  port: 8090

spring:
  application:
    name: authority
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/SSO?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

当用户访问除登录界面时,都需要提前认证,认证完成之后需要跳转到之前访问的路径上,并提供访问别的系统的权限。

实现逻辑,当用户访问任何路径时,都需要通过拦截器的校验,确认拥有访问的权限,才能放行通过,不具有访问权限的,重定向到 登录界面,并保存原有访问的页面路径,验证成功的时候跳转到原有页面

控制器

@Controller
public class IndexController {

    @Autowired
    UserRepository userRepository;

    /**
     * 将要跳转的路径
     */
    public String url;

    /**
     * 登录界面
     *
     * @return
     */
    @GetMapping("/index")
    public String index() {
        return "index";
    }

    /**
     * 登录界面
     *
     * @return
     */
    @GetMapping("/")
    public String index1() {
        return "index";
    }

    /**
     * 登录请求接口
     *
     * @param username 账号
     * @param password 密码
     * @param response
     * @return
     */
    @PostMapping("login")
    public String login(String username, String password, HttpServletResponse response) {
        // 用户登录
        boolean exists = userRepository.exists(Example.of(new User()
                .setUsername(username)
                .setPassword(password)));
        if (exists) {
            Cookie cookie = new Cookie("username", username);
            response.addCookie(cookie);
            // 如果正常访问即跳转到正常页面
            if (StringUtils.isEmpty(url)) {
                return "demo1";
            }
            // 如果之前存在访问的页面,认证完成即跳转会原有的页面
            return url;
        }
        return "index";
    }

    /**
     * 跳转到 demo2
     *
     * @return
     */
    @GetMapping("demo2")
    public String demo2() {
        return "demo2";
    }

    /**
     * 跳转到  demo1
     *
     * @return
     */
    @GetMappi=ng("demo1")
    public String demo1() {
        return "demo1";
    }

}

拦截器实现

@Component
public class CookieHandlerInterceptor implements HandlerInterceptor {

    @Autowired
    UserRepository userRepository;

    @Autowired
    IndexController indexController;

    /**
     * 执行方法之前
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取当前请求得路径 如果不是正常得登录界面请求 登录成功之后需要跳转到原来请求得界面上
        String servletPath = request.getServletPath();
        // 对不需要拦截得路径进行放行
        if ("/index".equals(servletPath) || "/".equals(servletPath) || "/login".equals(servletPath)) {
            return true;
        }
        if (!"/index".equals(servletPath) || !"/".equals(servletPath)) {
            indexController.url = servletPath;
        }
        Cookie[] cookies = request.getCookies();
        boolean exists = false;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String value = cookie.getValue();
                if (!StringUtils.isEmpty(value)) {
                    exists = userRepository.exists(Example.of(new User()
                            .setUsername(value)));
                }
            }
        }
        if (exists) {
            return true;
        } else {
            response.sendRedirect("/index");
        }
        return false;
    }
}

SpringBoot2.x之后不能生效,需要将拦截器添加到拦截器链路中,即:

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * Session 拦截处理器
     */
    @Autowired
    private CookieHandlerInterceptor cookieHandlerInterceptor;

    /**
     * 添加拦截器
     *
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.cookieHandlerInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }

}

其实拦截器还有第二种实现方式,即通过Filter接口实现

@Component
public class CookieFilter extends OncePerRequestFilter {

    @Autowired
    UserRepository userRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 获取当前请求得路径 如果不是正常得登录界面请求 登录成功之后需要跳转到原来请求得界面上
        String servletPath = request.getServletPath();
        IndexController indexController = new IndexController();
        // 对不需要拦截得路径进行放行
        if ("/index".equals(servletPath) || "/".equals(servletPath) || "/login".equals(servletPath)) {
            filterChain.doFilter(request, response);
        }
        if (!"/index".equals(servletPath) || !"/".equals(servletPath)) {
            indexController.url = servletPath;
        }
        Cookie[] cookies = request.getCookies();
        boolean exists = false;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String value = cookie.getValue();
                if (!StringUtils.isEmpty(value)) {
                    exists = userRepository.exists(Example.of(new User()
                            .setUsername(value)));
                }
            }
        }
        if (exists) {
            filterChain.doFilter(request, response);

        } else {
            response.sendRedirect("/");
        }
    }
}

其实也可以采用Session的方式实现,采用共享Session的方式,我这里只是简单的实现一下,其实在认证时可以结合SpringSecurity或者Shiro安全框架去整合JWT以保证信息的安全

界面

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<div align="center">
    <h1>请登录</h1>
    <form action="/login" method="post">
        <span>账号:</span><input name="username" type="text" value="zhang"><br>
        <span>密码:</span><input name="password" type="password" value="123456"><br>
        <button type="submit" style="margin: 10px 0">登录</button>
    </form>
</div>
</body>
</html>

demo1.htmldemo2.html只需要坐一下简单的区分,知道是哪个页面就行了

同域SSO其实不是很复杂,只是了解一下整个访问的过程,和需要做的一些限制即可,后续看看做后面两种的实现

同父域SSO跨域SSO

以上就是SpringBoot如何实现同域SSO(单点登录)的详细内容,更多关于SpringBoot 实现同域SSO的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot使用Redisson实现分布式锁(秒杀系统)

    前面讲完了Redis的分布式锁的实现,接下来讲Redisson的分布式锁的实现,一般提及到Redis的分布式锁我们更多的使用的是Redisson的分布式锁,Redis的官方也是建议我们这样去做的.Redisson点我可以直接跳转到Redisson的官方文档. 1.1.引入Maven依赖 <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter&l

  • springboot集成CAS实现单点登录的示例代码

    最近新参与的项目用到了cas单点登录,我还不会,这怎么能容忍!空了学习并搭建了一个spring-boot 集成CAS 的demo.实现了单点登录与登出. 单点登录英文全称是:Single Sign On,简称SSO. 含义:在多个相互信任的系统中,只要登录一个系统其他系统均可访问. CAS 是一种使用广泛的单点登录实现,分为客户端CAS Client和服务端 CAS Service,客户端就是我们的系统,服务端是认证中心,由CAS提供,我们需要稍作修改,启动起来就可以用.~~~~ 效果演示 ht

  • SpringBoot+Vue+Redis实现单点登录(一处登录另一处退出登录)

    一.需求 实现用户在浏览器登录后,跳转到其他页面,当用户在其它地方又登录时,前面用户登录的页面退出登录(列如qq挤号那种方式) 二.实现思路 用户在前端填写用户信息登录后,后台接收数据先去数据库进行判断,如果登录成功,创建map集合,以用户id为键,token为值,先通过当前登录用户的id去获取token,如果token存在说明该用户已经登录过,调用redis以token为键删除上个用户的信息,调用方法生成新token,并将token存入map集合,将用户信息存入redis,并将token存入c

  • SpringBoot集成Redisson实现分布式锁的方法示例

    上篇 <SpringBoot 集成 redis 分布式锁优化>对死锁的问题进行了优化,今天介绍的是 redis 官方推荐使用的 Redisson ,Redisson 架设在 redis 基础上的 Java 驻内存数据网格(In-Memory Data Grid),基于NIO的 Netty 框架上,利用了 redis 键值数据库.功能非常强大,解决了很多分布式架构中的问题. Github的wiki地址: https://github.com/redisson/redisson/wiki 官方文档

  • SpringBoot整合SSO(single sign on)单点登录

    1.单点登录三种常见的方式 (1)Session广播机制(Session复制) (2)使用Cookie+Redis实现 (3)使用token实现 2.单点登录介绍 举例: (1)引入jwt依赖 <!-- JWT--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> (2)创建JWTUtil

  • SpringBoot集成Redisson实现延迟队列的场景分析

    使用场景 1.下单成功,30分钟未支付.支付超时,自动取消订单 2.订单签收,签收后7天未进行评价.订单超时未评价,系统默认好评 3.下单成功,商家5分钟未接单,订单取消 4.配送超时,推送短信提醒 ...... 对于延时比较长的场景.实时性不高的场景,我们可以采用任务调度的方式定时轮询处理.如:xxl-job 今天我们采用一种比较简单.轻量级的方式,使用 Redis 的延迟队列来进行处理.当然有更好的解决方案,可根据公司的技术选型和业务体系选择最优方案.如:使用消息中间件Kafka.Rabbi

  • 基于SpringBoot解决CORS跨域的问题(@CrossOrigin)

    一.关于跨域介绍 在前后分离的架构下,跨域问题难免会遇见比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg. 网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源. 出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求. 例如,XMLHttpRequest和Fetch API遵循同源策略. 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非

  • vue+springboot前后端分离实现单点登录跨域问题解决方法

    最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登录咯,至于不知道什么是单点登录的同学,建议去找一下万能的度娘. 刚接到这个需求的时候,老夫心里便不屑的认为:区区登录何足挂齿,但是,开发的过程狠狠的打了我一巴掌(火辣辣的一巴掌)...,所以这次必须得好好记录一下这次教训,以免以后再踩这样的坑. 我面临的第一个问题是跨域,浏览器控制台直接报CORS,

  • 使用springboot结合vue实现sso单点登录

    本文实例为大家分享了springboot vue实现sso单点登录的具体代码,供大家参考,具体内容如下 项目结构: 开发工具:idea, maven3 静态文件下载地址 1.pom文件: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.or

  • 基于springboot和redis实现单点登录

    本文实例为大家分享了基于springboot和redis实现单点登录的具体代码,供大家参考,具体内容如下 1.具体的加密和解密方法 package com.example.demo.util; import com.google.common.base.Strings; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.Cipher; import javax.crypto.KeyG

  • 基于SpringBoot+Redis的Session共享与单点登录详解

    前言 使用Redis来实现Session共享,其实网上已经有很多例子了,这是确保在集群部署中最典型的redis使用场景.在SpringBoot项目中,其实可以一行运行代码都不用写,只需要简单添加添加依赖和一行注解就可以实现(当然配置信息还是需要的). 然后简单地把该项目部署到不同的tomcat下,比如不同的端口(A.B),但项目访问路径是相同的.此时在A中使用set方法,然后在B中使用get方法,就可以发现B中可以获取A中设置的内容. 但如果就把这样的一个项目在多个tomcat中的部署说实现了单

  • SpringBoot SSO轻松实现(附demo)

    前言 网上SSO的框架很多,此篇文章使用的是自写的SSO来实现简单的登录授权功能,目的在于扩展性,权限这方面,自写扩展性会好点. 提示:以下是本篇文章正文内容,下面案例可供参考 一.技术介绍 1.SSO是什么? 单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录.当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所

随机推荐