【2】从零开始做产品-单点登录

180 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

为了后续的产品社区,我们只需要建立一个登录服务即可将整个社区的登录全部管理,这个时候我们就需要用到单点登录,举个场景,假设我们的系统被切割为N个部分:商城、论坛、直播、社交…… 如果用户每访问一个模块都要登录一次,那么用户将会疯掉, 为了优化用户体验,我们急需一套机制将这N个系统的认证授权互通共享,让用户在一个系统登录之后,便可以畅通无阻的访问其它所有系统。

简而言之,单点登录可以做到:在多个互相信任的系统中,用户只需登录一次,就可以访问所有系统。

此时,我们就选择引入Sa-Token来实现单点登录

Sa-Token-SSO 由简入难划分为三种模式,解决不同架构下的 SSO 接入问题:

系统架构采用模式简介
前端同域 + 后端同 Redis模式一共享 Cookie 同步会话
前端不同域 + 后端同 Redis模式二URL重定向传播会话
前端不同域 + 后端不同 Redis模式三Http请求获取会话

我们这里为了更好的增加扩展性和可用性,选择模式三

1669015681488.jpg

**系统架构 ****采用模式 ****简介 **
前端同域 + 后端同 Redis模式一共享 Cookie 同步会话
前端不同域 + 后端同 Redis模式二URL重定向传播会话
前端不同域 + 后端不同 Redis模式三Http请求获取会话

我们这里为了更好的增加扩展性和可用性,选择模式三

1.简介

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证权限认证单点登录OAuth2.0分布式Session会话微服务网关鉴权 等一系列权限相关问题。

2.引入依赖、添加配置文件

①引入Sa-Token

<dependency>
   <groupId>cn.dev33</groupId>
   <artifactId>sa-token-spring-boot-starter</artifactId>
   <version>1.32.0</version>
</dependency>

②我们的项目是一个前后端分离微服务应用,所以我们不可采取单体架构(如单体内存来缓存token),故需要引入redis(或别的nosql)来实现中间件缓存,进行服务器间的token同步

<dependency>
   <groupId>cn.dev33</groupId>
   <artifactId>sa-token-dao-redis-jackson</artifactId>
   <version>1.32.0</version>
</dependency>

③redis连接池

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
</dependency>

④引入单点登录依赖

<dependency>
   <groupId>cn.dev33</groupId>
   <artifactId>sa-token-sso</artifactId>
   <version>1.32.0</version>
</dependency>
<!-- Http请求工具(在模式三的单点注销功能下用到,如不需要可以注释掉) -->
<dependency>
   <groupId>com.dtflys.forest</groupId>
   <artifactId>forest-spring-boot-starter</artifactId>
   <version>1.5.26</version>
</dependency>

⑤更改配置文件application.yml

# 端口
server:
  port: 9000

# Sa-Token 配置
sa-token:
   # ------- SSO-模式一相关配置 (非模式一不需要配置)
   # cookie:
       # 配置 Cookie 作用域
       # domain: stp.com

   # ------- SSO-模式二相关配置
  sso:
       # Ticket有效期 (单位: 秒),默认五分钟
      ticket-timeout: 300
       # 所有允许的授权回调地址
      allow-url: "*"
       # 是否打开单点注销功能
      is-slo: true

       # ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
       # 是否打开模式三
      isHttp: true
       # 接口调用秘钥(用于SSO模式三的单点注销功能)
      secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
       # ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)

spring:
   # Redis配置 (SSO模式一和模式二使用Redis来同步会话)
  redis:
       # Redis数据库索引(默认为0)
      database: 1
       # Redis服务器地址
      host: 127.0.0.1
       # Redis服务器连接端口
      port: 6379
       # Redis服务器连接密码(默认为空)
      password:

forest:
   # 关闭 forest 请求日志打印
  log-enabled: false

3.编写sso登录代码

@RestController
public class UserLoginController {


    @RequestMapping("/sso/*")
    public Object ssoRequest(){
        return SaSsoProcessor.instance.serverDister();
    }

    @Autowired
    private void configSso(SaSsoConfig sso) {
        // 配置:未登录时返回的View
        sso.setNotLoginView(() -> {
            String msg = "当前会话在SSO-Server端尚未登录,请先访问"
                    + "<a href='/sso/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
                    + "进行登录之后,刷新页面开始授权";
            return msg;
        });

        // 配置:登录处理函数
        sso.setDoLoginHandle((name, pwd) -> {
            // 此处仅做模拟登录,真实环境应该查询数据进行登录
            if("sa".equals(name) && "123456".equals(pwd)) {
                StpUtil.login(10001);
                StpUtil.getSession().set("userId",10001);
                return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue());
            }
            return SaResult.error("登录失败!");
        });

        // 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉)
        sso.setSendHttp(url -> {
            try {
                // 发起 http 请求
                System.out.println("------ 发起请求:" + url);
                return Forest.get(url).executeAsString();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        });
    }
}

此时小伙伴们是不是感觉不对劲,我们应该访问哪个接口去登陆呢?这是因为Sa-Token给我们封装了RestAPI,我们只需要直接调用http接口就可以了

登录接口:http://{host}:{port}/sso/doLogin

参数**是否必填 ****说明 **
name用户名
pwd密码

另外需要注意:此接口并非只能携带 name、pwd 参数,因为你可以在方法里通过 SaHolder.getRequest().getParam("xxx") 来获取前端提交的其它参数。

image.png

4.登录后session共享

我们可以在登录处理函数中进行设置session,从而在项目全局可以使用session中的用户信息

StpUtil.getSession().set("userId",user);

这里可以缓存基本数据类型或者是用户对象,获取的时候只需要转型一下即可

SysUser user = (SysUser) StpUtil.getSession().get("user");
String name = user.getName();

5.总结

这次分享就到这里了,Sa-Token还有好多好玩有意思的东西,大家可以自行去调研一下,国人的作品必须多多支持,也希望大家给点点关注,请作者喝杯咖啡熬夜写代码,感谢~

image.png