使用Sa-token实现单点登录

单点登录需求

     其实一直想写一个单点登录系统,现在的现状是公司内部有非常多项目的,然后每个项目一套登录系统,系统和系统之间存在单独的鉴权,每一个操作应用都需要登录一次的话,这样不仅仅用户体验不好,也会出现非常多重复的代码,于是单点登录的需求诞生了。

为何选择Sa-Token

     轻量级且开箱即用,如果你说为何不用shiro,那么我只能说它比shiro更加轻量更加好用,只需要简单的配置和写几行代码,即可实现登录功能。

简单使用sa-token

1.往项目中引入sa-token依赖

        <!-- sa-token鉴权模块 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>1.34.0</version>
        </dependency>

        <!-- Sa-Token 插件:整合SSO 【sso单点登录依赖】 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-sso</artifactId>
            <version>1.34.0</version>
        </dependency>

        <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) 【后续版本管理改为父级】 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-dao-redis-jackson</artifactId>
            <version>1.34.0</version>
        </dependency>

2.编写配置文件

# 端口
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: 
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池最大连接数
                max-active: 200
                # 连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms
                # 连接池中的最大空闲连接
                max-idle: 10
                # 连接池中的最小空闲连接
                min-idle: 0    

3.编写登录接口

// 会话登录接口 
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
    // 第一步:比对前端提交的账号名称、密码
    if("zhang".equals(name) && "123456".equals(pwd)) {
        // 第二步:根据账号id,进行登录 
        StpUtil.login(10001);
        return SaResult.ok("登录成功");
    }
    return SaResult.error("登录失败");
}

     上术代码已经实现了登录鉴权,但是我们也许可以注意到此处仅仅做了会话登录,并没有主动向前端返回 Token 信息。 是因为不需要吗?严格来讲是需要的,只不过 StpUtil.login(id) 方法利用了 Cookie 自动注入的特性,省略了你手写返回 Token 的代码。
     但在某些情况下,我们就是需要返回token给到前端,那应该如何操作呢?请往下看

     登录接口返回token信息

    // 登录接口
    @RequestMapping("doLogin")
    public SaResult doLogin(String username, String password) {
        // 第1步,先登录上
        StpUtil.login(10003);

        // 第2步,获取 Token  相关参数
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        // 第3步,返回给前端
        return SaResult.data(tokenInfo);
    }

     接口将会返回如下的数据:
在这里插入图片描述

     其中tokenName是请求头名称,tokenValue是请求头的值,将它们放入请求头即可保持登录态。

接口如何保持登录态

请求头放入token【登录接口返回】即可,比如:
在这里插入图片描述
controller代码如下:

    @RequestMapping("/userinfo")
    public Object userinfo() {

        // 自定义返回结果(模拟)
        return SaResult.ok()
                .set("id", StpUtil.getLoginId())
                .set("name", "zengjq")
                .set("sex", "男")
                .set("age", 18);
    }

是不是非常简单。我们通过StpUtil.getLoginId()即可拿到登录用户的id,但实际情况下我们往往需要拿到用户名称部门之类的更多信息,而登录态工具类StpUtil并未不能获取到,有同学肯定想到了,我拿用户id去访问数据库呀,但是每次都去查数据库那么它的压力就太大啦,其实sa-token提供了一个TokenSession
它是会话中的数据缓存组件,通过 Session 我们可以很方便的缓存一些高频读写数据,提高程序性能,例如:

// 在登录时缓存user对象 
StpUtil.getTokenSession().set("user", user);

// 然后我们就可以在任意处使用这个user对象
SysUser user = (SysUser) StpUtil.getTokenSession().get("user");

其实Sa-Token还提供了别的session类,这里不做赘述,有兴趣可以移步官方文档 sa-token session

使用拦截器实现鉴权

     我们来看拦截器代码:

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 新增登录校验拦截器 校验规则为 StpUtil.checkLogin() 登录校验。
        SaInterceptor saInterceptor = new SaInterceptor(handle -> StpUtil.checkLogin());

        // 注册 Sa-Token 拦截器
        registry.addInterceptor(saInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/doLogin", "/demo/**");  // 排除了/user/doLogin接口用来开放登录
    }
}

     这里的拦截器使用的是spring框架自带的,并不是sa-token提供的,所以它不仅仅可以用于sa-token的鉴权,还可以应用于spring框架的所有拦截操作

     实现完上述代码,sa-token 项目的简单鉴权就算是完成了。但其实sa-token还提供了许多功能,比如权限认证OAuth2.0分布式Session会话微服务网关鉴权 等等,有需要还是建议使用前看看官方文档 Sa-Token

聊聊Sa-Token的理解

     Sa-Token 我的理解是:它会更加希望你搭配一套统一的前端来使用,而不是每个系统都搭建一套登录系统,就算是在SSO单点登录模块里面,它依旧会给出 SSO整合-定制化登录页面 的教程,希望在未登录时跳转至我们编写好的页面,而不是去返回统一状态码给到前端。而我们公司会更加倾向于去返回统一json数据和不同的code状态码,其他交给前端自行判断。我们来看看我公司的处理。
     如果我想未登录时返回某个状态码,我们需要在异常处理类中加入NotLoginExceptionhandler
异常处理类代码如下:

@ControllerAdvice
public class GlobalExceptionHandler {
	private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	@ExceptionHandler(NotLoginException.class)
	@ResponseStatus(HttpStatus.OK)	// HttpStatus.OK是因为前端不基于httpStatus去判断接口是否异常
	@ResponseBody
	public SaResult handleNoHandlerFoundException(NotLoginException e) {
		log.error("用户未登录 ", e);
		// ErrorCode.LOGIN_REQUIRE.getCode() 是未登录时的与前端约定好的异常编码
		return SaResult.error(e.getMessage()).setCode(ErrorCode.LOGIN_REQUIRE.getCode());
	}


	@ExceptionHandler(SaTokenException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public SaResult handleSaTokenException(SaTokenException e) {
		log.error("sa-token抛出其他异常 ", e);
		return SaResult.error(e.getMessage());
	}
}

聊聊遇到的一些问题

当接口404时,spring会拦截后直接抛出异常信息:
在这里插入图片描述

上面的json其实并不是我们返回的,而是spring框架层返回的,如果我想改成自定义json,应该怎么处理呢?请往下看

自定义接口404响应信息
1、在配置文件中加入配置

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

throw-exception-if-no-handler-found表示当没有对应处理器时,允许抛出异常;而add-mappings表示是否为静态资源添加对应的处理器。而默认404异常不被全局处理器拦截,才导致未抛出异常。

2、在全局异常处理中捕获404

	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public SaResult handle404Error(NoHandlerFoundException e) {
		log.error("访问资源不存在", e);
		return new SaResult(404, "访问的资源不存在", null);
	}

其实一般我们会直接捕获Exception.class而不是特定的异常,只是如果你想做特殊处理,才需要类似上述的处理代码

好了,以上就是本次博客的全部内容,如有疑问,欢迎留言沟通

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
前后端分离是一种开发架构,将前端和后端的开发过程分开进行,前端主要负责用户界面展示和交互逻辑,后端负责数据处理和业务逻辑。而sa-token是一种单点登录的解决方案。 sa-token是基于Token的一个轻量级权限认证和申请令牌的工具,可以实现前后端分离项目的单点登录功能。它通过生成和验证Token令牌来实现用户身份认证。 在前后端分离的架构中,前端发送登录请求到后端,后端通过验证用户的账号和密码,如果验证成功,则生成一个Token令牌,并将该Token返回给前端。前端保存该Token,每次向后端发送请求时,需要在请求的Header中添加Token。后端通过获取请求Header中的Token,并进行验证,如果验证通过,则表示用户已登录。 sa-token提供了一些便捷的API,用于生成Token、验证Token、获取用户信息等操作。通过这些API,我们可以简便地实现单点登录的功能。sa-token还提供了一些定制化的配置选项,可以根据实际需求进行调整。 前后端分离的sa-token单点登录方案具有以下优点:简单易用、安全性高、扩展性强等。同时,由于前后端分离,使得前端和后端可以独立开发和部署,提高了开发效率和项目的可维护性。 总之,前后端分离sa-token单点登录是一种解决方案,通过Token令牌验证实现用户身份认证,适用于前后端分离的项目,具有诸多优点,可轻松实现单点登录功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值