Open-Starter-Security

一个支持令牌校验、鉴权功能的插件

🍪 快速开始

欢迎阅读 Open-Starter-Security 文档!

如果你有任何与 Open-Starter-Security 相关的问题,欢迎随时在 GitHub Discussions 上向我们的社区寻求帮助。

1. 添加 Maven 依赖

<dependency>
    <groupId>com.saucesubfresh</groupId>
    <artifactId>open-starter-security</artifactId>
    <version>1.0.4</version>
</dependency>

2. 启用安全拦截插件

启用 EnableSecurity 注解后会注入我们的拦截器

@EnableSecurity
@EnableLightRpcServer
@SpringBootApplication
public class JobAdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(JobAdminApplication.class, args);
    }
}

3. 配置白名单及其他参数

com:
  saucesubfresh:
    security:
      # 配置白名单
      ignore-paths:
        - '/captcha/**'
        - '/login/**'
      # 配置 jwt token 的 secret-key, 须注意长度,且要与 open-starter-oauth 配置的一致
      secret-key: 'ThisIsKeyThisIsKeyThisIsKeyThisIsKeyThisIsKeyThisIsKey'

4. 获取当前用户的用户信息

@Service
public class OpenJobServiceImpl extends ServiceImpl<OpenJobMapper, OpenJobDO> implements OpenJobService {

    private final ScheduleTaskExecutor scheduleTaskExecutor;
    private final ScheduleTaskManage scheduleTaskManage;
    private final OpenJobMapper openJobMapper;

    public OpenJobServiceImpl(ScheduleTaskExecutor scheduleTaskExecutor, ScheduleTaskManage scheduleTaskManage, OpenJobMapper openJobMapper) {
        this.scheduleTaskExecutor = scheduleTaskExecutor;
        this.scheduleTaskManage = scheduleTaskManage;
        this.openJobMapper = openJobMapper;
    }

    @Override
    public boolean save(OpenJobCreateDTO openJobCreateDTO) {
        String cronExpression = openJobCreateDTO.getCronExpression();
        if (!CronExpression.isValidExpression(cronExpression)){
            throw new ServiceException("Invalid cronExpression");
        }
        openJobCreateDTO.setCreateTime(LocalDateTime.now());
        // UserSecurityContextHolder.getUserId() 获取当前用户 userId
        openJobCreateDTO.setCreateUser(UserSecurityContextHolder.getUserId());
        int insert = openJobMapper.insert(OpenJobConvert.INSTANCE.convert(openJobCreateDTO));
        return insert != 0;
    }
}

常见问题

1. 如何实现权限访问控制?

常见的权限访问控制做法有如下两种

1、路径比对

一般的系统在权限设计上,都会分为角色、权限(RBAC),复杂一点的可能会有用户组、组织之类的概念。

用户的权限是写死的,对应于后台的接口或者资源,是没办法改变的,一般不对用户开放修改权限。

管理员用户可以通过给角色分配权限的方式,来实现访问控制。

即分析当前访问路径所需要的权限,检查当前用户是否具有该权限,做一个对比,根据对比结果来决定当前用户是否可以访问该资源。

这种做法的好处是代码的入侵性不高,不需要再每个接口上加注解。但相对来说,显得不那么直观。

具体实现可以参考 Open-Admin

2、使用注解的方式

有些小型的系统或许压根就不需要权限,只需要给用户分配角色,没有给角色分配权限这一过程。这样的话,角色也是不可变的,就可以根据角色来做访问控制了。

在需要某个角色才能访问的方法上添加 PreAuthorization 注解,在该 starter 中已提供该实现,具体可以看 DefaultAccessDeniedHandler,

该默认实现适合简单的权限管理系统,如系统中只有一种角色,比如只有 admin 角色,而某些接口只有拥有 admin 角色才能访问。

参考 Open-Crawler

@Validated
@RestController
@RequestMapping("/user")
public class CrawlerUserController {

  @Autowired
  private CrawlerUserService crawlerUserService;

  @DeleteMapping("/delete")
  @PreAuthorization(value = "admin")
  public Result<Boolean> delete(@RequestBody @Valid DeleteDTO deleteDTO) {
    return Result.succeed(crawlerUserService.deleteById(deleteDTO));
  }

}

注意事项

  1. HandlerInterceptor 搭配注解使用时,注解只能用在 Controller 中, 也就是说我们的自定义注解 PreAuthorization 只能用在 Controller