[Java 基于SSO实现单点登录]

 

目录

前言:

基于 Token 的 SSO 实现单点登录 

实现 SSO 的单点登录通常需要以下步骤:

第一步:

创建一个 UserService 类,用于处理用户登录和生成 Token。

创建一个 TokenCache 类,用于存储 Token 和对应的用户信息。

在 Auth Center 中创建一个 LoginController 类,用于处理用户登录请求。

创建一个应用(App)项目,用于演示单点登录。

在 App 中创建一个 LoginController 类,用于处理用户登录请求。

在 App 中创建一个 LogoutController 类,用于处理用户注销请求。

在 App 中创建一个 AuthFilter 类,用于拦截请求并验证 Token。

在 App 中配置 AuthFilter。

单点登录流程:

AppConfig 和 AuthFilter 两个类在单点登录流程中作用。


前言:

      🔣方法千千万,单点登录不一般,记录一个小笔记,虽然生活很累,但是依然励志前行

基于 Token 的 SSO 实现单点登录 

SSO(Single Sign-On,单点登录)是一种身份验证机制,它允许用户使用一组凭据(例如用户名和密码)登录到多个应用程序或系统中,而无需在每个应用程序或系统中单独进行身份验证。在 SSO 中,用户只需要登录一次,就可以访问所有与 SSO 集成的应用程序或系统,这样可以提高用户体验和安全性。

实现 SSO 的单点登录通常需要以下步骤:

  • 创建一个认证中心(Auth Center)应用程序,用于处理用户身份验证和生成 Token。

  • 在 Auth Center 中创建一个用户数据库或集成现有的用户数据库,用于存储用户信息和凭据。

  • 在 Auth Center 中实现身份验证机制,例如用户名和密码验证、双因素身份验证等。

  • 在 Auth Center 中生成一个 Token,并将 Token 存储到缓存中,以便后续验证。

  • 在每个需要集成 SSO 的应用程序中,创建一个 Token 验证机制,用于验证 Token 是否有效。

  • 在每个应用程序中,创建一个登录页面,用于接收用户凭据并向 Auth Center 发送身份验证请求。

  • 在每个应用程序中,将 Token 存储到 Cookie 或其他存储介质中,以便后续验证。

  • 在每个应用程序中,创建一个拦截器或过滤器,用于拦截请求并验证 Token。

  • 在每个应用程序中,根据 Token 中的用户信息显示对应的页面或资源。

  • 在每个应用程序中,创建一个注销机制,用于删除 Token 并注销用户。

通过以上步骤,可以实现基于 Token 的 SSO 单点登录。在这种方案中,用户只需要登录一次,就可以访问所有与 SSO 集成的应用程序,这样可以提高用户体验和安全性。


第一步:

  • 创建一个认证中心(Auth Center)项目,用于处理用户登录和生成 Token。

  • 在 Auth Center 中创建一个 User 类,用于存储用户信息。

public class User {
    private String username;
    private String password;
    // 其他用户信息

    // 构造函数、getter 和 setter 方法
}
  • 创建一个 UserService 类,用于处理用户登录和生成 Token。

public class UserService {
    private static final Map<String, User> userMap = new HashMap<>();

    static {
        // 初始化用户数据
        User user1 = new User("user1", "password1");
        User user2 = new User("user2", "password2");
        userMap.put(user1.getUsername(), user1);
        userMap.put(user2.getUsername(), user2);
    }

    public static String login(String username, String password) {
        User user = userMap.get(username);
        if (user != null && user.getPassword().equals(password)) {
            // 生成 Token
            String token = UUID.randomUUID().toString();
            // 将 Token 存储到缓存中
            TokenCache.put(token, user);
            return token;
        }
        return null;
    }

    public static User getUserByToken(String token) {
        return TokenCache.get(token);
    }
}
  • 创建一个 TokenCache 类,用于存储 Token 和对应的用户信息。

public class TokenCache {
    private static final Map<String, User> tokenMap = new ConcurrentHashMap<>();

    public static void put(String token, User user) {
        tokenMap.put(token, user);
    }

    public static User get(String token) {
        return tokenMap.get(token);
    }
}
  • 在 Auth Center 中创建一个 LoginController 类,用于处理用户登录请求。

@RestController
public class LoginController {
    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        String token = UserService.login(username, password);
        if (token != null) {
            return token;
        }
        return "login failed";
    }
}
  • 创建一个应用(App)项目,用于演示单点登录。

  • 在 App 中创建一个 HomeController 类,用于处理首页请求。

@RestController
public class HomeController {
    @GetMapping("/")
    public String home(HttpServletRequest request) {
        String token = request.getHeader("token");
        User user = UserService.getUserByToken(token);
        if (user != null) {
            return "Welcome, " + user.getUsername();
        }
        return "Please login first";
    }
}
  • 在 App 中创建一个 LoginController 类,用于处理用户登录请求。

@RestController
public class LoginController {
    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        // 向认证中心发送登录请求
        String url = "http://localhost:8080/login?username=" + username + "&password=" + password;
        RestTemplate restTemplate = new RestTemplate();
        String token = restTemplate.postForObject(url, null, String.class);
        if (token != null) {
            // 将 Token 存储到 Cookie 中
            Cookie cookie = new Cookie("token", token);
            cookie.setPath("/");
            cookie.setMaxAge(3600);
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            response.addCookie(cookie);
            return "login success";
        }
        return "login failed";
    }
}
  • 在 App 中创建一个 LogoutController 类,用于处理用户注销请求。

@RestController
public class LogoutController {
    @GetMapping("/logout")
    public String logout(HttpServletRequest request) {
        // 从 Cookie 中获取 Token
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("token")) {
                    String token = cookie.getValue();
                    // 从缓存中删除 Token
                    TokenCache.get(token);
                    // 删除 Cookie
                    cookie.setMaxAge(0);
                    HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
                    response.addCookie(cookie);
                    return "logout success";
                }
            }
        }
        return "logout failed";
    }
}
  • 在 App 中创建一个 AuthFilter 类,用于拦截请求并验证 Token。

public class AuthFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String token = httpRequest.getHeader("token");
        User user = UserService.getUserByToken(token);
        if (user != null) {
            chain.doFilter(request, response);
        } else {
            httpResponse.sendRedirect("/login");
        }
    }
}

  • 在 App 中配置 AuthFilter。

@Configuration
public class AppConfig {
    @Bean
    public FilterRegistrationBean<AuthFilter> authFilterRegistration() {
        FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new AuthFilter());
        registration.addUrlPatterns("/*");
        registration.setName("authFilter");
        registration.setOrder(1);
        return registration;
    }
}
  • authFilterRegistration() 方法的作用是将 AuthFilter 过滤器注册到应用程序中,并指定过滤器的执行顺序和 URL 模式,以确保该过滤器能够正确地拦截请求并验证 Token。
  • 启动 Auth Center 和 App 两个项目,访问 App 的首页,会提示需要登录,点击登录按钮,输入用户名和密码,登录成功后会跳转到首页,显示欢迎信息。在其他浏览器或标签页中访问 App 的首页,会自动跳转到登录页面。在已登录的浏览器或标签页中访问 App 的其他页面,会自动跳转到对应页面,无需再次登录。

单点登录流程:

  • 用户在 App 中访问需要登录的页面,如果没有登录,则跳转到登录页面。

  • 用户在登录页面输入用户名和密码,App 向 Auth Center 发送登录请求。

  • Auth Center 验证用户名和密码,如果验证通过,则生成一个 Token,并将 Token 存储到缓存中。

  • Auth Center 返回 Token 给 App。

  • App 将 Token 存储到 Cookie 中,并跳转到首页。

  • 用户在 App 中访问其他页面时,App 会从 Cookie 中获取 Token,并向 Auth Center 发送 Token 验证请求。

  • Auth Center 验证 Token,如果验证通过,则返回用户信息。

  • App 根据用户信息显示对应页面。

  • 用户在任意浏览器或标签页中访问 App,如果已经登录,则无需再次登录,直接跳转到对应页面。

AppConfig 和 AuthFilter 两个类在单点登录流程中作用。

  • AppConfig 类是用来配置 AuthFilter 的,AuthFilter 是一个过滤器,用于拦截请求并验证 Token。在单点登录流程中,用户在访问需要登录的页面时,AuthFilter 会拦截请求并检查是否存在 Token,如果存在,则验证 Token 是否有效,如果有效,则允许用户访问页面,否则跳转到登录页面。因此,AuthFilter 在单点登录流程中起到了验证 Token 的作用。
  • 而 AppConfig 类则是用来配置 AuthFilter 的,它通过创建一个 FilterRegistrationBean 对象来注册 AuthFilter,并指定了过滤器的 URL 模式、名称和执行顺序。在单点登录流程中,AppConfig 类的作用是将 AuthFilter 注册到应用程序中,并指定x过滤器的执行顺序,以确保 AuthFilter 在其他过滤器之前执行。因此,AppConfig 在单点登录流程中起到了注册和配置 AuthFilter 的作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/28740.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32单片机(六)TIM定时器 -> 第二节:TIM定时中断练习(定时器定时中断和定时器外部时钟)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

docker数据管理---数据卷,数据卷容器

在Docker中&#xff0c;数据卷&#xff08;data volumes&#xff09;和数据卷容器&#xff08;data volume containers&#xff09;是用于在容器之间共享和持久化数据的两种不同的机制。 一、数据卷 数据卷是一个特殊的目录或目录&#xff0c;可以绕过容器文件系统的常规层&a…

【RabbitMQ教程】第六章 —— RabbitMQ - 延迟队列

&#x1f4a7; 【 R a b b i t M Q 教程】第六章—— R a b b i t M Q − 延迟队列 \color{#FF1493}{【RabbitMQ教程】第六章 —— RabbitMQ - 延迟队列} 【RabbitMQ教程】第六章——RabbitMQ−延迟队列&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人…

2023年前端面试高频考点HTML5+CSS3

目录 浏览器的渲染过程⭐⭐⭐ CSS 、JS 阻塞 DOM 解析和渲染 回流&#xff08;重排&#xff09;和重绘⭐⭐ 选择器 ID选择器、类选择器、标签选择器&#xff08;按优先级高到低排序&#xff09;⭐⭐ 特殊符号选择器&#xff08;&#xff1e;,,~&#xff0c;空格&#xff0…

Stopwatch工具类计时器探究

搬砖的我们 特别是Java开发的童鞋们, 经常需要通过记录开始时间和结束时间&#xff0c;然后通过计算差值&#xff0c;得到时间差&#xff0c;如下面的代码&#xff1a; long start System.currentTimeMillis(); long end System.currentTimeMillis(); System.out.println(…

医疗设备都在用哪些晶振?

医疗设备是指用于医疗诊断、治疗、监测等方面的各种设备。随着科技的不断发展&#xff0c;医疗设备的功能不断增强&#xff0c;精度和稳定性也得到了大幅提升。在这些医疗设备中&#xff0c;晶振是非常重要的元件之一。本文将介绍医疗设备中常用的晶振类型及其特点。 一、晶振…

P20[6-8]编码器接口测速(软)

与外部中断编码器逻辑不同,此处编码器使用的是定时器方法 1.Encoder编码器部分: #include "stm32f10x.h" // Device header void Encoder_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCm…

阿里云弹性公网EIP收费价格表

阿里云弹性公网EIP怎么收费&#xff1f;EIP地域不同价格不同&#xff0c;EIP计费模式分为包年包月和按量付费&#xff0c;弹性公网IP可以按带宽收费也可以按使用流量收费&#xff0c;阿里云百科分享阿里云弹性公网IP不同地域、不同计费模式、按带宽和按使用流量详细收费价格表&…

Java泛型的使用

1.什么是泛型&#xff1f; 所谓泛型&#xff0c;就是允许在定义类、接口时通过 一个标识 表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时&#xff08;例如&#xff0c;继承或实现这个接口&#xff0c;用这个类型声明变量、创建对象时&#…

取石子游戏——算法与编程

取石子游戏 目录 问题描述输入输出格式输入格式&#xff1a;输出格式&#xff1a; 输入输出样例输入样例#1&#xff1a;输出样例#1&#xff1a;提示信息 算法尼姆博奕 代码 问题描述 A l i c e Alice Alice和 B o b Bob Bob在玩取石子游戏&#xff0c;摆在他们面前的有 n n n堆…

RFID期末复习总结

一.概念部分 1.基础概念 射频识别无线电频率识别RFID 应答器&#xff1a;存放识别信息的电子数据载体 阅读器&#xff1a;将识别信息从应答器中读出&#xff08;还可以写入数据&#xff09; 应答器是统称&#xff0c;在各种专业场合有专业名字&#xff0c;比如射频卡&#…

2022 年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题

2022 年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题 一. 逻辑推理&#xff1a;第 26~55 小题&#xff0c;每小题 2 分&#xff0c;共 60 分。下列每题给出的 A、B、C、D、E 五个选项中&#xff0c;只有一项是符合试题要求的。 26.百年党史充分揭示了中国共产党为什么…

object类clone、finalize

2 什么是API API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;是一些预先定义的函数。目的是提供应用程序与开发人员基于某软件可以访问的一些功能集&#xff0c;但又无需访问源码或理解内部工作机制的细节. API是一种通用功能集,有时公…

Linux操作系统——第四章 进程间通信

目录 进程间通信介绍 进程间通信目的 进程间通信发展 进程间通信分类 管道 System V IPC POSIX IPC 管道 什么是管道 匿名管道 管道读写规则 管道特点 命名管道 创建一个命名管道 匿名管道与命名管道的区别 命名管道的打开规则 system V共享内存 共享内存示意…

TS系列之keyof详解,示例

文章目录 前言一、keyof是什么总结 前言 如果你用过TS的工具类型&#xff0c;Partial、Required、Pick、Record。那么你可能看过他们内部实现都有共同点就是keyof关键字。即使没有见过&#xff0c;那么下面就一起来了解一下&#xff0c;keyof关键字的详细作用吧。 一、keyof是…

基于Java家政服务网站系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

今天面了个京东拿 38K 出来的,让我见识到了基础的天花板

今年的春招结束了&#xff0c;而秋招也马上要开始了&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 …

应聘求职自荐信优秀范文5篇

应聘求职自荐信优秀范文篇1 尊敬的领导&#xff1a; 您好!衷心的感谢您在百忙之中翻阅我的这份材料&#xff0c;并祝愿贵单位事业欣欣向荣&#xff0c;蒸蒸日上! 我是哈尔滨理工大学测控技术及通信工程学院________届毕业生&#xff0c;自从今日大学之后&#xff0c;高考后的轻…

Python实现面向对象版学员管理系统

如有错误&#xff0c;敬请谅解&#xff01; 此文章仅为本人学习笔记&#xff0c;仅供参考&#xff0c;如有冒犯&#xff0c;请联系作者删除&#xff01;&#xff01; 1.1需求分析 1.1.1使用面向对象编程思想完成学员管理系统的开发&#xff0c;具体如下&#xff1a; 系统要求…

Linux防火墙学习笔记12

iptables nat表应用案例&#xff1a; nat表作用&#xff1a; 导流 nat表作用位置&#xff1a; KVM或者OpenStack中虚拟机或云主机与外部通信。&#xff08;云主机导流&#xff09; Docker管理的容器与外部通信 nat表规则动作所对应的链&#xff1a; SNAT 源地址转换 应…
最新文章