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

 更新时间:2021年05月13日 09:43:36   作者:是小张啊  
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。即在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统,本文将介绍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的资料请关注脚本之家其它相关文章!

相关文章

  • Mybatis批量删除多表

    Mybatis批量删除多表

    MyBatis的作用我想不用多说,今天说说MyBatis中的批量删除操作。 需要的朋友一起看看吧
    2017-10-10
  • Java编程中快速排序算法的实现及相关算法优化

    Java编程中快速排序算法的实现及相关算法优化

    这篇文章主要介绍了Java编程中快速排序算法的实现及相关算法优化,快速排序算法的最差时间复杂度为(n^2),最优时间复杂度为(n\log n),存在优化的空间,需要的朋友可以参考下
    2016-05-05
  • 浅谈servlet中的request与response

    浅谈servlet中的request与response

    下面小编就为大家带来一篇浅谈servlet中的request与response。小编觉得挺不错的,现在就分享给大家,也给大家做个参加。一起跟随小编过来看看吧
    2016-07-07
  • springboot中mybatis多数据源动态切换实现

    springboot中mybatis多数据源动态切换实现

    在开发中,动态数据源配置还是用的比较多的,比如在多数据源使用方面,又或者是在多个DB之间切换方面。这里给出一个动态数据源的配置方案,感兴趣的可以了解一下
    2021-07-07
  • java打印指定年月份的日历

    java打印指定年月份的日历

    这篇文章主要为大家详细介绍了java打印指定年、指定月份的日历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • Java AQS中CyclicBarrier回环栅栏的使用

    Java AQS中CyclicBarrier回环栅栏的使用

    这篇文章主要介绍了Java中的 CyclicBarrier详解,CyclicBarrier没有显示继承哪个父类或者实现哪个父接口, 所有AQS和重入锁不是通过继承实现的,而是通过组合实现的,下文相关内容需要的小伙伴可以参考一下
    2023-02-02
  • 如何用Java的swing编写简单计算器

    如何用Java的swing编写简单计算器

    这篇文章主要给大家介绍了关于如何用Java的swing编写简单计算器的相关资料,通过本文可以设计一个图形界面的简易计算器,完成简单的算术运算符,可以完成加法、减法、乘法、除法和取余运算,需要的朋友可以参考下
    2023-12-12
  • Java中的DecimalFormat用法解析

    Java中的DecimalFormat用法解析

    这篇文章主要介绍了Java中的DecimalFormat用法解析,DecimalFormat是Java中用于格式化数字的类,它提供了一种简单而灵活的方式来格式化数字,包括指定小数位数、千位分隔符、货币符号等,需要的朋友可以参考下
    2023-10-10
  • 解决lambda表达式内出现异常无法throw抛出的问题

    解决lambda表达式内出现异常无法throw抛出的问题

    这篇文章主要介绍了lambda表达式内出现异常无法throw抛出的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • MyBatis延迟加载实现步骤详解

    MyBatis延迟加载实现步骤详解

    这篇文章主要介绍了MyBatis延迟加载实现步骤详解,​ MyBatis中的延迟加载,也成为懒加载,是指在进行关联查询时,按照设置的延迟规则推迟对关联对象的查询,延迟加载可以有效的减少数据库的压力,需要的朋友可以参考下
    2023-10-10

最新评论