基于redis+springboot从零开始设计一个类阿里系的单点登录

SpringBoot + Redis实现单点登录 1.为什么有单点登录 web应用早已从久远的单系统发展到如今由多系统组成的应群,面对如此众多的系统,用户难道要一个一个登录,这显然不现实。单点登录就是为了解决这一问题。 web应用的复杂性应该由系统内部承担,而不是用户。无论web系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问web系统的整个应用群与访问单个系统一样,登录一次就够了。 2.单点登录的实现方案 1.ses... 阅读详情

前言

★ 这里是小冷的博客
✓ 优质技术好文见专栏
个人公众号,分享一些技术上的文章,以及遇到的坑
当前系列:单点登录
源代码 git 仓库 ‘
单点登录代码地址 仓库地址

生活中的事情

最近购物的时候遇到一个很奇妙的情况,我发现我只在天猫登录了,之后去淘宝买东西的时候,完全不虚要登录,这是为什么?

image-20220119194805596

image-20220119000920797

首先我去天猫登录一下,之后刷新淘宝来看看,登录天猫之后,直接去刷新淘宝页面

image-20220119001400861

image-20220119001424858

我们会发现淘宝也登录了,为什么可以这么方便呢?这里就用到了单点登录的概念。

什么是单点登录

单点登录在大型网站里使用得非常频繁,例如,阿里旗下有淘宝、天猫、支付宝,阿里巴巴,等网站,还有背后的成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协 作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯掉。

单点登录在大型网站里使用得非常频繁,例如,阿里旗下有淘宝、天猫、支付宝,阿里巴巴,阿里妈妈, 阿里妹妹等网站,还有背后的成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协 作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯 掉。

所以,单点登录要解决的就是,用户只需要登录一次就可以访问所有相互信任的应用系统。

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO 并 不能算是一种架构,只能说是一个解决方案。SSO核心意义就一句话:一处登录,处处登录;一处注 销,处处注销。就是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统,即 用户只需要记住一组用户名和密码就可以登录所有有权限的系统。

使用“单点登录”还是SOA时代的需求之一。在面向服务的架构中,服务和服务之间,程序和程序 之间的通讯大量存在,服务之间的安全认证是SOA应用的难点之一,应此建立“单点登录”的系统体系能 够大大简化SOA的安全问题,提高服务之间的合作效率。

简谈SSO的发展

早期的单机部署

早期我们开发web应用都是所有的包放在一起打成一个war包放入tomcat容器来运行的,所有的功能,所 有的业务,后台管理,门户界面,都是由这一个war来支持的,这样的单应用,也称之为单体应用,因为十分不好 扩展和拆分。

在单体应用下,用户的登录以及权限就显得十分简单:过滤器,用户登录成功后,把相关信息放入会话 中,HTTP维护这个会话,再每次用户请求服务器的时候来验证这个会话即可

验证登录的这个会话就是session,维护了用户状态,也就是所谓的HTTP有状态协议,我们经常可以在浏览 器中看到JSESSIONID,这个就是用来维持这个关系的key。

分布式集群部署

由于网站的访问量越来也大,单机部署已经是巨大瓶颈,所以才有了后来的分布式集群部署。
例如:如 果引入集群的概念,1单应用可能重新部署在3台tomcat以上服务器,使用nginx来实现反向代理, 此时,这个 session就无法在这3台tomcat上共享,用户信息会丢失,所以不得不考虑多服务器之间的session同步问 题,这就是单点登录的来源。

image-20220118195145433

多种解决方案

单点登录的实现方案,一般就包含以下三种:

  • Cookies
  • Session同步
  • 分布式Session方式

目前的大型网站都是采用分布式Session的方式。我先从cookie的实现谈起,你就能很清楚的知道为什 么需要分布式session方式实现单点登录。

基于Cookie的单点登录

最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。 用户登录父应用之后,应用返回 一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验, 校验通过则登录当前用户。

不难发现以上方式把信任存储在客户端的Cookie中,这种方式很容易令人质疑:

  • Cookie不安全
  • 不能跨域实现免登

对于第一个问题,通过加密Cookie可以保证安全性,当然这是在源代码不泄露的前提下。如果Cookie 的加密算法泄露,攻击者通过伪造Cookie则可以伪造特定用户身份,这是很危险的。 对于第二个问题,不能跨域实现免登更是硬伤。所以,才有了以下的分布式session方案

分布式session单点登录

我们这次就是基于redis的单点登录

例如,阿里有很多系统分割为多个子系统,独立部署后,不可避免的会遇到会话管理的问题,类似这样 的电商网站一般采用分布式Session实现。 再进一步可以根据分布式Session+redis,建立完善的单点登录或账户管理系统。

流程运行:

  1. 用户第一次登录时,将会话信息(用户Id和用户信息),比如以用户Id为Key,写入分布式 Session;
  2. 用户再次登录时,获取分布式Session,是否有会话信息,如果没有则调到登录页
  3. 一般采用Cache中间件实现,建议使用Redis,因此它有持久化功能,方便分布式Session宕机后, 可以从持久化存储中加载会话信息;
  4. 存入会话时,可以设置会话保持的时间,比如15分钟,超过后自动超时;

结合Cache中间件实现的分布式Session,可以很好的模拟Session会话。

常见方案

实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他系统如何验证这个信任的有效 性,

因此要点也就以下两个:

  • 存储信任 服务器生产
  • 验证信任 ~ 拿到服务器再次验证~

身份认证技术:

  • cas(单点登录)
  • Spring Security OAuth2(第三方登录授权:QQ登陆)
  • jwt (客户端token:原生)

安全控制框架:

  1. spring-security
  2. shiro

设计思路与环境

环境

JDK 11

maven3.6.2

redis 6

springboot 2.x

设计与编写思路

单点登录验证中心:

  • islogin:验证是否有token,并且设置对应user的限时key
  • checklogin:检查有没有token,没有的话就带着请求地址转发到login登录,如果有token就返回token给客户端做二次请求校验
  • verify: 校验token是否正确,返回布尔值
  • 注销

客户端思路:

  • 请求工具封装
  • 拦截器:http请求验证是否有登陆过,如果没有转发到检查登录
  • 服务器登录完整之后会转发会客户端,拦截器判断是否有token参数,获取token请求验证中心二次验证,通过的话放行

功能流程图

image-20220119003340402

SS0_server主要实现

客户端拦截器请求处理:

拦截器:请求islogin判断有没有登录

server:返回登录判断结果,如果检查到redis有token就生成对应的限时userkey

拦截器:如果没有登陆过,并且token为null那么就请求checklofin

server:检查没有token,代表第一次请求转发到login登录并且返回携带token返回

拦截器:检测到token请求二次校验,

server:返回与redis和tokenmap的校验结果

拦截器:根据结果判断是否重新请求checklogin或者通过

下面代码实现上述流程的server处理

服务端核心功能

logincontroller
  • islogin:验证是否有token,并且设置对应user的限时key
  • checklogin:检查有没有token,没有的话就带着请求地址转发到login登录,如果有token就返回token给客户端做二次请求校验
  • verify: 校验token是否正确,返回布尔值
  • 注销
/**
 * @projectName: SSO_self
 * @package: com.hyc.sso_server.controller
 * @className: loginController
 * @author: 冷环渊 doomwatcher
 * @description: TODO
 * @date: 2022/1/9 12:44
 * @version: 1.0
 */
@Controller
public class loginController {
    @Autowired
    StringRedisTemplate redisTemplate;

    @RequestMapping("/index")
    public String login() {
        return "login";
    }

    UserAndPassword userAndPassword = new UserAndPassword();

    @RequestMapping("/login")
    public String login(String username, String password, String redirectUrl, RedirectAttributes model) {
        System.out.println("loginuser" + "\t" + username + "\t" + "password" + "\t" + password);
        //模拟登录数据库设计
        if ("admin".equals(username) && "123456".equals(password)) {
            //校验成功
            //    1. 创建token
            String token = UUID.randomUUID().toString();
            System.out.println("token创建成功==>" + token);
            //    2. 需要把令牌信息收入到数据库中
            //if (redisTemplate.hasKey("token")) {
            //    redisTemplate.delete("token");
            //}
            redisTemplate.opsForSet().add("token", token);
            userAndPassword.setUsername(username);
            userAndPassword.setPassword(password);
            userTokenMap.tokenmap.put(username, token);
            //    3.重定向到redirecturl
            model.addAttribute("token", token);
            model.addAttribute("username", username);
            System.out.println(redirectUrl);
            return "redirect:" + redirectUrl;
        }
        //如果密码不正确,重新的返回登录页面
        System.out.println("用户密码不正确,重复回到登录页面");
        model.addAttribute("redirectUrl", redirectUrl);
        return "login";
    }

    //检查登录
    @RequestMapping("/checkLogin")
    public String checklogin(String redirectUrl, Model model) {
        String getgenretetoken = userTokenMap.tokenmap.get(userAndPassword.getUsername());
        Set<String> token = redisTemplate.opsForSet().members("token");
        if (!token.contains(getgenretetoken)) {
            //    没有全局会话的话 跳转带统一认证中心的登陆界面
            // 携带转发来的地址 一起转发回去
            model.addAttribute("redirectUrl", redirectUrl);
            return "login";
        } else {
            //   全局会话 取出令牌信息 重定向到 redirecturl
            model.addAttribute("token", getgenretetoken);
            model.addAttribute("username", userAndPassword.getUsername());
            return "redirect:" + redirectUrl;
        }
    }

    @RequestMapping("/islogin")
    @ResponseBody
    public String islogin() {
        String getgenretetoken = userTokenMap.tokenmap.get(userAndPassword.getUsername());
        Set<String> token = redisTemplate.opsForSet().members("token");
        if (!token.contains(getgenretetoken)) {
            return "false";
        } else {
            String islogin = null;
            if (redisTemplate.hasKey(userAndPassword.getUsername())) {
                islogin = redisTemplate.opsForValue().get(userAndPassword.getUsername());
            } else {
                islogin = String.valueOf(RedisUtils.cacheValue(userAndPassword.getUsername(), "true", 30));
            }
            return islogin;
        }
    }

    //校验token 是否是验证中心产生
    @RequestMapping("/verify")
    @ResponseBody
    public String verifytoken(String token) {
        if (redisTemplate.opsForSet().isMember("token", token)) {
            System.out.println("服务端token验证ok===>" + token);
            return "true";
        }
        return "false";
    }

    @RequestMapping("/loginOut")
    @ResponseBody
    public String loginout() {

        RedisUtils.redisTemplate.delete("token");
        RedisUtils.redisTemplate.delete("islogin");
        System.out.println("删除成功");
        return "注销成功";
    }
}

redis监听器

检查userkey是否过期,redis触发过期时间就删除对应的token

配置:

@Configuration
public class RedisConfiguration {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    //配置 将spring的 redis链接工厂放入监听容器
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        return redisMessageListenerContainer;
    }

    //将自定义的监听器放入容器中
    @Bean
    public keyexpireListener keyExpiredListener() {
        return new keyexpireListener(this.redisMessageListenerContainer());
    }
}

自定义监听器

/**
 * @projectName: SSO_self
 * @package: com.hyc.sso_server.Listener
 * @className: keyexpireListener
 * @author: 冷环渊 doomwatcher
 * @description: TODO
 * @date: 2022/1/11 17:30
 * @version: 1.0
 */
public class keyexpireListener extends KeyExpirationEventMessageListener {

    //日志
    private static final Logger LOGGER = LoggerFactory.getLogger(keyexpireListener.class);

    /**
     * @param listenerContainer must not be {@literal null}.
     */
    public keyexpireListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    //实现信息方法,打印监听日志,后续可能对过期key处理
    /*redis key 过期:pattern=__keyevent@*__:expired,channel=__keyevent@0__:expired,key=name
     * 测试完毕
     * */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String channel = new String(message.getChannel(), StandardCharsets.UTF_8);
        //过期的key
        String key = new String(message.getBody(), StandardCharsets.UTF_8);
        //  如果登录令牌过期,则删除token 要求用户重新登录
        for (String s : userTokenMap.tokenmap.keySet()) {
            if (key.equals(s)) {
                RedisUtils.redisTemplate.opsForSet().remove("token", userTokenMap.tokenmap.get(key));
                System.out.println("删除成功");
            }
        }
        LOGGER.info("redis key 过期:pattern={},channel={},key={}", new String(pattern), channel, key);
    }
}

客户端核心

SSO请求工具
public class SSOClientUtil {

    private static Properties ssoProperties = new Properties();
    public static String SERVER_URL_PREFIX; //统一认证中心地址
    public static String CLIENT_HOST_URL; //当前客户端地址

    static {
        try {
            ssoProperties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        SERVER_URL_PREFIX = ssoProperties.getProperty("server-url-prefix");
        CLIENT_HOST_URL = ssoProperties.getProperty("client-host-url");
    }

    /**
     * 当客户端请求被拦截,跳往统一认证中心,需要带redirectUrl的参数,统一认证中心登录后回调的地址
     */
    public static String getRedirectUrl(HttpServletRequest request) {
        //获取请求URL
        return CLIENT_HOST_URL + request.getServletPath();
    }

    /**
     * 根据request获取跳转到统一认证中心的地址,通过Response跳转到指定的地址
     */
    public static void redirectToSSOURL(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String redirectUrl = getRedirectUrl(request);
        StringBuilder url = new StringBuilder(50)
                .append(SERVER_URL_PREFIX)
                .append("/checkLogin?redirectUrl=")
                .append(redirectUrl);
        response.sendRedirect(url.toString());
    }

    public static void redirectToSSOURL(HttpServletRequest request, HttpServletResponse response, String token) throws IOException {
        String redirectUrl = getRedirectUrl(request);
        StringBuilder url = new StringBuilder(50)
                .append(SERVER_URL_PREFIX)
                .append("/checkLogin?redirectUrl=")
                .append(redirectUrl)
                .append("&token=")
                .append(token);
        response.sendRedirect(url.toString());
    }

    /**
     * 获取客户端的完整登出地址
     */
    public static String getClientLogOutUrl() {
        return CLIENT_HOST_URL + "/loginOut";
    }

    /**
     * 获取认证中心的登出地址
     */
    public static String getServerLogOutUrl() {
        return SERVER_URL_PREFIX + "/loginOut";
    }
}

对应配置文件

server-url-prefix=http://www.sso.com:8001
client-host-url=http://www.tm.com:8003
http请求工具
/**
 * @projectName: SSO_self
 * @package: com.hyc.http
 * @className: HttpUitl
 * @author: 冷环渊 doomwatcher
 * @description: TODO
 * @date: 2022/1/9 0:52
 * @version: 1.0
 */
public class HttpUitl {
    public static String sendHttpRequest(String httpurl, Map<String, String> parms) throws Exception {
        //定义需要访问的地址
        URL url = new URL(httpurl);
        //连接 URL
        HttpURLConnection connect = (HttpURLConnection) url.openConnection();
        //请求方式
        connect.setRequestMethod("POST");
        //携带参数
        connect.setDoOutput(true);
        if (parms != null && parms.size() > 0) {
            StringBuffer sb = new StringBuffer();
            for (Map.Entry<String, String> par : parms.entrySet()) {
                sb.append("&").append(par.getKey()).append("=").append(par.getValue());
            }
            connect.getOutputStream().write(sb.substring(1).toString().getBytes("UTF-8"));
        }
        // 发起请求
        connect.connect();
        //接受返回值
        String response = StreamUtils.copyToString(connect.getInputStream(), Charset.forName("UTF-8"));
        return response;
    }
}

拦截器
  • 请求校验
  • 二次校验
  • 拦截判断
/**
 * @projectName: SSO_self
 * @package: com.hyc.ssoclienttb.interceptor
 * @className: ssoInterceptor
 * @author: 冷环渊 doomwatcher
 * @description: TODO
 * @date: 2022/1/9 20:20
 * @version: 1.0
 */
public class ssoInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String httpuri = SSOClientUtil.SERVER_URL_PREFIX + "/islogin";
        HashMap<String, String> isloginparms = new HashMap<>();
        String islogin = HttpUitl.sendHttpRequest(httpuri, isloginparms);
        if (islogin.equals("true")) {
            return true;
        }
        //判断地址栏是否有携带token参数
        String token = request.getParameter("token");
        System.out.println(token);
        if (!StringUtils.isEmpty(token)) {
            System.out.println("检测到token信息,需要去sso服务器验证!");
            //    token 信息不为空 说明拥有令牌,我们需要去认证中心检查这个令牌,以防伪造
            String httpURL = SSOClientUtil.SERVER_URL_PREFIX + "/verify";
            HashMap<String, String> parms = new HashMap<>();
            //放入登出的位置和token
            parms.put("token", token);
            try {
                String isverify = HttpUitl.sendHttpRequest(httpURL, parms);
                if ("true".equals(isverify)) {
                    //    如果返回的字符串是true 说明这个token是由统一认证中心产生的
                    System.out.println("检测到token信息,验证通过");
                    return true;
                } else {
                    SSOClientUtil.redirectToSSOURL(request, response);
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //不存在用通过我们的认证工具类 转发到对应的认证界面 ssoclientuitl
        SSOClientUtil.redirectToSSOURL(request, response);
        return false;
    }

实现效果

此时redis的keys的状态

image-20220119011839039

这里我们启动三个项目

image-20220119011906060

访问两个客户端

  • http://www.sso.com:8001/checkLogin?redirectUrl=http://www.tm.com:8003/tmall
  • http://www.sso.com:8001/checkLogin?redirectUrl=http://www.tb.com:8002/taobao

image-20220119011948500

image-20220119012000005

可以看出我们这两个都是没有登陆过的,接下来我们登录其中一个客户端

image-20220119012057882

此时查看redis状态

image-20220119012106532

之后刷新另一个

image-20220119012118976

会发现淘宝客户端登录之后,天猫不需要登录,也可以直接进入首页。

SpringBoot前后台分离项目使用Redis实现SSO单点登录 在这个方法中,我们使用`registry.addMapping`指定了路由,并设置了允许所有来源的跨域请求(`allowedOrigins("*")`),同时还配置了允许的HTTP方法和请求头。采用web集群进行的服务配置,可以得到较好的处理性能,同时也可以保证高可用的机制,但是有一个最关键性的问题就是在于Session共享与分配,从早期的开发来讲,Session共享是在tomcat中配置的(Tomcat提供了一个扩展的支持)。.addPathPatterns("/**") // 拦截所有路径。 阅读详情

相关推荐

SpringBoot集成redis+cookie实现分布式单点登录

因为涛哥刚进入公司,易哥在开发一个系统的迭代版本。现在有一个问题是考虑到在分布式部署时,移动端和PC sessionid的不同要实行单点登录和数据的共享。让我想想该如何实现,首先我就想到的是用redis,然后又去考虑什么异地登录的情况。结果回来通宵用jwt+redis+cookie集成实现了,刚开始想的也是直接在地址栏输入然后后台界面校验登录状态。后来发现思维有点混乱,想想倒不如重新想想。然后自己理清思路,决定用uuid+redis+cookie来实现。最后也就有了现在的最终版。

m0_73311735的博客 1380

单点登录一:springboot项目使用redis、springSecurity、jwt实现单点登录的demo

springboot项目使用redis、springSecurity、jwt实现单点登录,写一个最基础的demo。容易理解

qq_35515283的博客 2460

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

基于springboot和redis实现的单点登录 1、pom.xml配置 server: port: 8888 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/users?useSSL=false&serverTimezone=GMT%2B8 username: root password: sas...

java_jntm的博客 856

单点登录(SSO)的设计与实现

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。我们目前的系统存在诸多子系统,而这些子系统是分别部署在不同的服务器中,那么使用传统方式的session是无法解决的,我们需要使用相关的单点登录技术来解决。当我们访问其中一个前台系统需要登录才可以访问的页面时,自动跳转到登录中心进行登录,登录后再次跳转回该前台系统,该前台系统可以获取登录名。

一位Java开发工程师 3189

基于SpringBoot实现简易的单点登录系统(提供gitee源码)

单点登录的英文名全称叫做:Single Sign On,简称SSO,是指在同一个账号平台下的多个子系统中,用户只需要登录一次,就可以访问其余所有相互的信任的系统,比如支付宝旗下有天猫和淘宝,当我登陆了淘宝以后,天猫也会同步进行登录,就不需要们再一个个去进行登录操作了,简而言之便是,多个互相信任的子系统同步登陆。这里我主要通过Token拼接在URL上面实现的单点登录,整体项目写的非常简易,仅用于提供一个学习思路,对单点登录有个基础的了解。

黄团团的个人博客 8119

vscode+latex+bib文献管理

下载vscode 安装插件`` 在setting.json中配置 在.tex文件中编写论文内容,然后左侧TEX侧边栏中编译,如下图所示,中文用xelatex,英文用pdflatex;编译成功后,就可以查看pdf版本的论文了,我一般在浏览器显示。 涉及到文献编译:XXX.bib中存储文献管理内容;XXX.tex是文章内容,使用xelatex编译后会生成XXX.aux,ctrl+⋅ctrl+·ctrl+⋅打开命令行窗口,输入bibtex XXX(可以对aux文件进行编译,不需要加后缀),然后再xelatex.

小卜妞的博客 2548

基于SpringBoot实现单点登录系统

单点登录系统设计思路:Spring4 Java配置方式整合HttpClient,Redis ,MySql和Springboot的简易教程。 在传统的系统,或者是只有一个服务器的系统中。Session在一个服务器中,各个模块都可以直接获取,只需登录一次就进入各个模块。若在服务器集群或者是分布式系统架构中,每个服务器之间的Session并不是共享的,这会出现每个模块都要登录的情况。这时候需要通过单点登录系统(Single Sign On)将用户信息存在Redis数据库中实现Session共享的效果。从而实现一

jike11231的博客 7972

AI开发提效10倍:从需求到部署的全流程实战指南(附Prompt模板)

用AI开发不是“偷懒”,而是把时间花在更有价值的地方——原来花80%时间写重复代码,现在用AI搞定后,能把精力放在“优化用户体验”“提升系统性能”这些核心工作上,这才是AI给开发者的真正红利。如果你还没开始用AI做开发,建议从“写一个简单接口”“补一段注释”开始尝试,先用起来再优化方法。记住:AI是工具,不是对手,学会驾驭它,你会发现开发效率提升的同时,还能告别无效加班。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1531

Springboot集成JWT+Redis实现单点登录和同一账号只允许在一处登录

功能简述:JWT+Redis实现单点登录功能的同时,也实现同一个账号只能在一台设备上登录,实现方式并非是建立长连接,因为长连接是比较消耗系统性能的。这里只是简单的redis方式实现。 什么是单点登录? 单点登录的英文名叫做:Single Sign On(简称SSO)。 在最开始的单体架构(或者说单系统)当中,所有的代码都放在一个项目当中,传统的登录流程是 用户登录—>登录校验(校验用户名密码)—>将用户名等信息放入session当中—>成功登录。 这样就可以从session当中获取用.

weixin_43412919的博客 1万+

Halcon手眼标定实战:从九点标定到机械臂精准抓取(附完整代码)

本文详细介绍了Halcon手眼标定技术在实际工业场景中的应用,重点讲解了九点标定法在机械臂精准抓取中的实现步骤和优化技巧。通过对比Eye-to-Hand和Eye-in-Hand两种模式的特点,提供完整的代码示例和误差分析,帮助工程师快速掌握标定技术,提升自动化系统的精度和稳定性。

weixin_29100927的博客 460

Python 复现AlexNet框架代码

【代码】Python 复现AlexNet框架代码。

Quintin 2420

SpringBoot + Redis + Shiro + JWT单点登录主流安全框架

SpringBoot集成Redis、Shiro、JWT

欢迎。 2675

华为OD机试 - 猴子吃桃 - 二分查找(Java 新系统 100分)

每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天优快云在线答疑。

学Java,找哪吒 3850

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

SpringBoot+Vue+Redis实现单点登录(一处登录,另一处退出登录) 一、需求 实现用户在浏览器登录后,跳转到其他页面,当用户在其它地方又登录时,前面用户登录的页面退出登录(列如qq挤号那种方式) 二、实现思路 用户在前端填写用户信息登录后,后台接收数据先去数据库进行判断,如果登录成功,创建map集合,以用户id为键,token为值,先通过当前登录用户的id去获取token,如果tok...

JAVA-XH 5153

华为OD机考双机位C卷 - 螺旋数字矩阵 (Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 数字螺旋矩阵(OD上机考试双机位C卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 3218

国科大学习资料--高级软件工程-复习题选择题答案

国科大学习资料–高级软件工程(罗铁坚 魏峻 刘丹)-复习题选择题答案 ’‘

无名何许人的博客 1166

[SpringBoot]单点登录

【实现手段】当用户提交登录请求时,就需要获取用户的IP地址与设备信息,当验证登录通过后,将此用户的JWT、IP地址、设备信息全部存入到Redis中,后续,当客户端提交请求后,在。)中,首先检查Redis中的信息,如果此JWT在Redis中存在(例如白名单),则视为有效,所以,当退出登录时,只需要在Redis中将对应的JWT删除即可。目前的代码中,将管理员的权限列表存储在JWT中,导致JWT数据太长,并且,权限数据应该视为敏感数据,不应该表现在JWT中。以上问题都可以结合Redis的应用来解决!

YJH000_的博客 6085

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

SpringBoot+Redis实现单点登录

很久之前公司的平台需要接入其他公司的系统,当时弄了一个单点登录,很强大。最近有个朋友问到怎么实现,其实实现的方式很多,如今有出现了很多更牛X的方式。从开始有人用cookie实现,到共享session,redis实现或者其他的。其实都是为了一个目的,让别的系统知道你的信息,也就是共享。 共享的方式也有很多,通过数据库,通信,其他。下面我将自己做的介绍下,我的比较简单,也有局限性。我采用redis共享...

jifen_black的博客 7884

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

单点登录系统实现基于SpringBoot

单点登录系统实现 单点登录系统实现基于SpringBoot 今天的干货有点湿,里面夹杂着我的泪水。可能也只有代码才能让我暂时的平静。通过本章内容你将学到单点登录系统和传统登录系统的区别,单点登录系统设计思路,Spring4 Java配置方式整合HttpClient,整合Redis ,HttpClient简易教程。还在等什么?撸起袖子开始干吧! 效果图:8081端口是sso系统,其他两个808...

f45056231p的博客 1225

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SpringBoot+Redis完成一个简单的单点登录

一、需求分析 当用户在浏览器端登录后,再到别处登录时,前一次的登录信息会删除,再回到前一次页面需要重新登录。 二、实现思路 用户在浏览器端输入用户名和密码登录,后端接收请求到数据库验证,若存在此用户,则将用户的id为key,用户信息存入token为value。通过当前登录用户的id去获取token,如果token存在说明该用户已经登录过,调用redis以token为键删除上个用户的信息,调用方法生...

weixin_44214162的博客 1119

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

title: 基于SpringBoot+Redis的Session共享与单点登录 date: 2019-07-23 02:55:52 categories: 架构 author: mrzhou tags: SpringBoot redis session 单点登录 基于SpringBoot+Redis的Session共享与单点登录 前言 使用Redis来实现Session共享,其实网上已经...

蜜友的博客 1288

java单点登录框架_单点登录系统实现基于SpringBoot

今天的干货有点湿,里面夹杂着我的泪水。可能也只有代码才能让我暂时的平静。通过本章内容你将学到单点登录系统和传统登录系统的区别,单点登录系统设计思路,Spring4 Java配置方式整合HttpClient,整合Redis ,HttpClient简易教程。还在等什么?撸起袖子开始干吧!效果图:8081端口是sso系统,其他两个8082和8083端口模拟两个系统。登录成功后检查Redis数据库中是否有...

weixin_32842805的博客 1831

Spring Boot+OAuth2,一个注解搞定单点登录!

需要先说一下,松哥最近写的教程,都是成系列的,有一些重复的东西写来写去就没意思了,所以每一篇文章都默认大家已经懂了前面的内容了,因此下文有任何看不懂的地方,建议一定先看下相关系列: Spring Security 系列: 挖一个大坑,Spring Security 开搞! 松哥手把手带你入门 Spring Security,别再问密码怎么解密了 手把手教你定制 Spring Security 中...

江南一点雨的专栏 3万+
上一篇: 2022: 暴杀表达式, 脚踩逆波兰的时候到了
下一篇: 十大经典排序算法:快速排序debug分析排序过程
冷环渊
博客等级 码龄7年 1130粉丝 176原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷环渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值