Springboot插件集成(三)-权限认证插件sa-token

993 阅读4分钟

前言

有一次在码云闲逛被它的标题吸引到了,"一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!",既然你都说简单、优雅了,那我倒要看看是不是真如你所说,然后我就是一顿淦。了解完之后我只能说句牛逼!不用自定义Realm,不用写全局过滤器,各种配置文件你都不用写!只需

    StpUtil.login(Object id);// 标记当前会话登录的账号id

这就完成了登录授权。同学们是不是已经合不上了,当你用过shiro、SpringSecurity后你就会知道这个框架用起来有多爽。下面做个简单的权限认证系统,加深一下理解。

一、依赖引入

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>  
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.28.0</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-jwt</artifactId>
    <version>1.28.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.28.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!-- hutool java工具库 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.19</version>
</dependency>

二、完整application.yml

spring:
 profiles:
   active: dev
 datasource:
   driver-class-name: com.mysql.cj.jdbc.Driver
   url: jdbc:mysql://127.0.0.1:3306/testdb?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
   username: root
   password: root
 application:
   name: springboot-test
 redis:
   # Redis数据库索引(默认为0)
   database: 0
   # 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
mybatis-plus:
 configuration:
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

server:
 port: 8011
# Sa-Token配置
sa-token:
 # token名称 (同时也是cookie名称)
 token-name: Authorization
 # token有效期 设为一天 (必定过期) 单位: 秒
 timeout: 86400
 # token临时有效期 (指定时间无操作就过期) 单位: 秒
 activity-timeout: 1800
 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
 is-concurrent: true
 # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
 is-share: false
 # 是否尝试从请求体里读取token
 is-read-body: false
 # 是否尝试从header里读取token
 is-read-head: true
 # 是否尝试从cookie里读取token
 is-read-cookie: false
 # token前缀
 token-prefix: "Bearer"
 # token风格
 token-style: uuid
 # jwt秘钥
 jwt-secret-key: jdagsderfsgsderwq
 # 是否输出操作日志
 is-log: false

注意!!这个系统用到了Mybatis-Plus,不懂的同学可以看看我之前的文章**《Springboot插件集成(二)- MyBatis增强插件Mybatis-Plus》

三、业务代码

1、服务层

public interface UserService extends IService<User> {
   
   User selectUserByUserName(String userName);
}

2、业务层处理

@Service("UserService")
public class UserServiceImpl  extends ServiceImpl<UserMapper,User> implements UserService {


    @Override
    public User selectUserByUserName(String userName) {
        User user = this
                .getOne(new QueryWrapper<User>()
                .lambda()
                .eq(User::getUserName, userName));


        return user;
    }
}

3、控制层

@Slf4j
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class LoginController {

    private final UserService userService;


    // 测试登录  ---- http://localhost:8011/test/doLogin?username=test3&password=123
    @GetMapping("/doLogin")
    public SaResult doLogin(String username, String password) {
        User user = userService.selectUserByUserName(username);
        if (user == null) {
            log.info("登录用户:{} 不存在.", username);
            return SaResult.error("用户不存在");
        }
        if (!password.equals(user.getPassword())) {
            log.info("登录用户:{} 账号密码不匹配.", username);
            return SaResult.error("账号密码不匹配");
        }
        // 标记当前会话登录的账号id
        StpUtil.login(user.getId());
        // 生成token
        String tokenValue = StpUtil.getTokenInfo().getTokenValue();
        // 缓存user对象
        StpUtil.getTokenSession().set("loginUser", user);
        Map<String, String> result = new HashMap<String, String>();
        result.put("token", tokenValue);
        return SaResult.ok().setData(result);
    }

    // 测试注销  ---- http://localhost:8011/test/logout
    @GetMapping("/logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }

    // 测试获取登录用户名  ---- http://localhost:8011/test/getSession
    @GetMapping("/getSession")
    public SaResult getSession() {
        // 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
        StpUtil.checkLogin();
        User userInfo = (User) StpUtil.getTokenSession().get("loginUser");
        String userName = userInfo.getUserName();
        return SaResult.ok().setData(userName);

    }

}

4、domain

@Data
@TableName("t_user")
public class User {
    private Long id;
    private String userName;
    private String password;
    private Integer age;
    private String email;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

5、路由拦截配置类

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册Sa-Token的路由拦截器
        registry.addInterceptor(new SaRouteInterceptor())
                //拦截所有
                .addPathPatterns("/**")
                //排除/test/doLogin 用于开放登录
                .excludePathPatterns("/test/doLogin");
    }
}

6、异常处理类(处理鉴权失败产生的异常)

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NotLoginException.class)
    public SaResult handleAccessDeniedException(NotLoginException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
        return SaResult.error().setCode(HttpStatus.HTTP_UNAUTHORIZED).setMsg(StrUtil.format("请求地址'{}',认证失败,无法访问系统资源", requestURI));
    }

}

四、测试

1、测试登录方法

image.png

可以看到已经登录成功,并返回了token。

2、测试获取当前登录用户名

首先不提交token看看

image.png

不提交token时,显示认证失败,无法访问。

再加上token提交看看

image.png

可以看到已成功获取到了当前登录的用户名。

3、测试登出

image.png

显示已经登录成功,再用刚才的token访问获取当前登录用户名接口试试。

image.png

可以看到刚才的token已经失效了。

结语

sa-token还能完成很多的功能,等待同学们去探索。最后附上sa-token官方文档的链接,有兴趣的可以去一探究竟。Sa-Token官方文档