com.ruoyi

├── ruoyi-ui // 前端框架 [80]

├── ruoyi-gateway // 网关模块 [8080]

├── ruoyi-auth // 认证中心 [9200]

├── ruoyi-api // 接口模块

│ └── ruoyi-api-system // 系统接口

├── ruoyi-common // 通用模块

│ └── ruoyi-common-core // 核心模块

│ └── ruoyi-common-datascope // 权限范围

│ └── ruoyi-common-datasource // 多数据源

│ └── ruoyi-common-log // 日志记录

│ └── ruoyi-common-redis // 缓存服务

│ └── ruoyi-common-seata // 分布式事务

│ └── ruoyi-common-security // 安全模块

│ └── ruoyi-common-swagger // 系统接口

├── ruoyi-modules // 业务模块

│ └── ruoyi-system // 系统模块 [9201]

│ └── ruoyi-gen // 代码生成 [9202]

│ └── ruoyi-job // 定时任务 [9203]

│ └── ruoyi-file // 文件服务 [9300]

├── ruoyi-visual // 图形化管理模块

│ └── ruoyi-visual-monitor // 监控中心 [9100]

├──pom.xml // 公共依赖

ruoyi-api

└── ruoyi-api-system

里面存放的系统内各个模块都会用到的东西。比如用户信息、用户角色、部门信息

ruoyi-auth

认证中心登录、注册等相关的控制器

ruoyi-common

ruoyi-common通用模块

└── ruoyi-common-log

日志记录@Log 注解的相关操作

注:框架里的各种自定义的注解的功能,都在对应的模块里用AOP横切进来的。

└── ruoyi-common-security

└──aspect

└──PreAuthorizeAspect

注解鉴权鉴权不通过直接报错

└──auth

└──authUtil

用户权限工具类但是这个类只像是一个接口,具体的实现都在authLogic里面

└──authLogic

用户权限工具类的具体实现逻辑

ruoyi-gateway

└── filter

└──AuthFilter

全局过滤器每个请求进来都会先进入过滤器,鉴权

└── service

└──ValidateCodeService

验证码处理配置信息在nacos中的gateway配置文件中。(可配置验证码类型:计算 or 字符)

ruoyi-modules

└── ruoyi-system

└── SysMenuController

菜单管理相关控制器(操作菜单信息)刚进入系统时获取菜单路由也在这

└── SysRoleController

角色管理相关控制器(操作角色信息)

└── SysUserController

用户管理相关控制器(操作用户信息)

问题记录

请求执行顺序

因为前端是发送请求到网关。所以请求会先到网关的全局过滤器,并将用户信息设置到请求头 com.ruoyi.gateway.filter.AuthFilter 通过网关的过滤器后,会进入拦截器 com.ruoyi.common.security.config.WebMvcConfig 被拦截的请求,会进入自定义的请求头拦截器,从请求头中获取用户信息存到线程中 com.ruoyi.common.security.interceptor.HeaderInterceptor 进入controller中 controller执行结束后会删除当前线程。

未登录拦截

在未登录的情况下,直接访问 http://localhost:81/index ,不会进入首页,而是被弹到登录页。

首先会在前端做验证,从Cookie中获取token,判断是否有token,没有则直接弹到登录页:

若通过前端的话,请求到达后端,会进入网关的全局过滤器,判断token的有效性,无效就弹回:

发现一个bug,如果手动修改了浏览器Cookie中的token,会导致后端token解析报错,导致所有页面都无法访问,包括登录页面。必须要手动把token删除,才能正常访问。

每个请求进来都会先进入过滤器,鉴权

权限注解

若依框架中自定义了三个权限注解

@RequiresLogin登录认证:只有登录之后才能进入该方法。@RequiresPermissions权限认证:必须具有指定权限才能进入该方法。@RequiresRoles角色认证:必须具有指定角色标识才能进入该方法

这三个注解的具体实现是通过AOP横切来实现的:PreAuthorizeAspect类

定义三个注解为切入点

@Pointcut和@Around联合注解

对被代理的Method对象进行注解检查

访问每个菜单都是有权限要求的。

数据范围注解

框架中自定义了1个数据范围注解:@DataScope

这个注解可以传3个参数,不过一般只用2个。

由于系统中数据众多,角色众多,总不可能让普通员工也能看到所有员工的信息吧,所以需要为每种角色分配数据权限范围。比如:董事长可以看所有员工数据,部门主管可以看部门和子部门里所有员工的数据,普通员工只能看本部门员工信息。

若依把这个功能用注解封装了起来。

数据库中的sys_role表中存储了角色的数据范围data_scope字段:

数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)新增角色时默认为’1’

展示数据但是需要判断数据范围的方法,只需要在service实现类上增加@DataScope注解,并告知sql语句中的部门表的别名或者用户表的别名,注解的切面类会根据数据表中data_scope字段来为sql语句中拼接相应的sql语句(因为sql语句中有多表连接,所以需要传别名),并把需要拼接的sql语句放到point(被代理的方法)的参数对象里,让mapper.xml可以读取到需要拼接的sql。

当前框架中需要用到数据范围注解的:

根据条件分页查询角色数据:只能获取范围内的角色列表。比如,当前员工只能看到本部门里有哪些角色。查询部门管理数据:只能获取数据范围内的部门列表。比如,当前员工可以看到本部门和本部门和子部门列表。根据条件分页查询用户列表:只能获取范围内的用户列表。比如,当前员工只能看到本部门的用户列表。根据条件分页查询已分配用户角色列表:只能获取范围内的角色的已分配用户列表,比如,当前员工只能获取本部门内已分配该角色的用户列表。根据条件分页查询未分配用户角色列表:获取范围内的未分配该角色的用户列表,比如,当前员工只能获取本部门内未分配该角色的用户列表。

获取当前用户信息

若依框架中获取当前操作用户信息是从当前线程中获取的,当前线程中存放了用户信息。这里有一个关键的东西:TransmittableThreadLocal,这个是alibaba提供的一个工具包中的类,主要作用就是解决线程池场景下的变量传递问题。这里会存储当前用户的信息。

package com.ruoyi.common.core.context;

/**

* 获取当前线程变量中的 用户id、用户名称、Token等信息

* 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取

*

* @author ruoyi

*/

public class SecurityContextHolder{

private static final TransmittableThreadLocal> THREAD_LOCAL = new TransmittableThreadLocal<>();

...

}

每个外部请求进来都会先到网关的过滤器中,过滤器跳过不需要验证的路径后,就会获取请求里的token,并解析token得到用户信息,把信息塞到请求头中,把信息传递到拦截器中。

tomcat会为每一个请求分配一个线程,拦截器里的自定义请求头拦截器就会把请求头中的信息存到当前线程当中

这样的话,当前线程在进入Controller前就已经携带了用户的相关信息了,所以可以直接在代码中获取用户信息。

map中的数据get()后不会被删除。get()后会删除的是python里面的queue。差点混乱了。

方法成功执行结束后,会删除当前线程。

代码问题

循环查库

如果有很多的角色,就循环查库了

⭐注意⭐

对象赋值

一个对象直接赋给另一个新的对象,这种赋值只是地址赋值,两个对象指向同一个地址,只要其中任何一个改变相应的值,两个都会一起变化。并不是数据拷贝。

BeanUtils.copyProperties();是数据拷贝。

User user = new User(1, "zhangSan", 25, student);

User newUser=user;

修改形参

Java在调用方法时,在方法内部修改形参会不会影响到实参:

如果是基本类型,则实参不会变(传的是值)如果是对象,则实参会改变(传的是引用)

八股文都差点忘了

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: