信息发布→ 登录 注册 退出

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

发布时间:2026-01-11

点击量:
目录
  • 如何实现同域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的资料请关注其它相关文章!

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!