springSecurity权限控制

权限控制:不同的用户可以使用不同的功能。

我们不能在前端判断用户权限来控制显示哪些按钮,因为这样,有人会获取该功能对应的接口,就不需要通过前端,直接发送请求实现功能了。所以需要在后端进行权限判断。(前端防君子,后端防小人。

授权流程:springSecurity会默认使用FilterSecurityInterceptor进行权限校验,会从SecurityContextHolder中获取authentication,获取权限信息进行判断。

所以需要我们做的就是把用户的权限信息存入authentication。

那么SecurityContextHolder中的权限信息是从哪里获取的呢,前面SecurityContextHolder中的认证用户信息是从redis中获取的,权限信息也一样。

我们先说说权限控制的方案:1、springSecurity提供注解;2、配置

注解权限控制是我们经常用的,我就只说这个方案了。

使用权限控制注解,需要在SecurityConfig配置类中开启配置:

@EnableGlobalMethodSecurity(prePostEnabled = true)

java 复制代码
@Configuration
//开启权限控制注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
     .....
}

我们能用的权限控制注解有很多,但真正经常用的只有@PreAuthorize就是在访问之前进行权限判断。写在controller层的请求方法上。

@PreAuthorize("hasAuthority('test')")

这里其实是去调用hasAuthority方法去判读权限,返回true即有权限。test为权限名

java 复制代码
@RestController
@RequestMapping
public class HelloController {
    @GetMapping("/hello")
    //这里其实是去调用hasAuthority方法去判读权限,返回true即有权限.test为权限名,这里只能填一个权限
    @PreAuthorize("hasAuthority('test')")
    public String hello(){
        return "hello";
    }

至于 权限名的定义和权限内容的定义 在后面定义。

注解类方法:

@PreAuthorize("hasAuthority('权限名')")

除了前面用的hasAuthority方法外,还有其他的校验方法,当然我们也可以自定义校验方法。

hasAuthority('')方法:只能填一个权限。

hasAnyAuthority('','','')方法:可以传入多个权限,其中用户有任意一个权限都可以访问。

hasRole('')方法:要求有对应角色才可以访问。它内部会把我们传入的角色参数拼接上 ROLE_ 后在去比较,所以需要对用户的权限也要有 ROLE_ 这个前缀。

hasAnyRole('','','')方法:要求有对应任意角色才可以访问。它内部也会把我们传入的角色参数拼接上 ROLE_ 后在去比较,所以需要对用户的权限也要有 ROLE_ 这个前缀。

同时权限是实体类User类的属性:

java 复制代码
@Data
@NoArgsConstructor
//@AllArgsConstructor
public class LoginUser implements UserDetails {

    //需要定义User对象来封装用户信息。
    private User user;

    //该用户的权限信息
    private List<String> permissions;
    public LoginUser(User user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }

    //问题:当我们把logUser存入redis中时,redis默认不会把SimpleGrantedAuthority对象序列化。
    //解决:我们不需要把SimpleGrantedAuthority存入redis,我们只需把权限信息permissions存入即可
    //通过permissions反序列化即可获取authorities,所以需要忽略SimpleGrantedAuthority,不要对它序列化
    @JSONField(serialize = false)
    private List<SimpleGrantedAuthority> authorities;
    @Override //实际springSecurity获取权限信息是调用的该方法,重写该方法。
    public Collection<? extends GrantedAuthority> getAuthorities() {
        //优化:如果每次获取权限都进行集合转换,有点浪费。我们只第一次去集合转换,后续获取直接返回之前转换好的
        //即把List<SimpleGrantedAuthority> authorities定义为成员变量。
        if(authorities!=null){
            return authorities;
        }
        authorities = permissions.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }
}

然后去数据库中查询用户权限:

到数据库中查询权限信息:

RBAC权限模型(Role-Based Access Control):基于角色的权限控制。这是目前最常被开发者使用也是相对易用、通用权限模型。

在数据库中,我们会创建一个用户表,一个权限表(记录着权限功能说明和权限名),一个用户可以有多个权限,不好表达,所以我们又引入了一个角色表,里面有很多角色,在创建个角色权限管理表,每种角色对应不同的多种功能,为角色赋予不同的权限。比如:图书馆管理系统中的角色:图书管理员(权限:添加、查询、删除等等);借阅者(权限:查询、借阅)。同时,一个用户可能会有多种身份,需要将用户与角色关联起来。

这就是RBAC模型(最少都是5张表)

5表联合查询用户权限:role为角色表,menu为菜单表(可以理解为权限表)

XML 复制代码
<mapper namespace="org.example.springSecurity.mapper.MenuMapper">
    <select id="selectPermsByUserId" resultType="java.lang.String">
        select
        distinct m.perms
        from sys_user_role ur
        Left join `sys_role` r on ur.role_id = r.id
        Left join `sys_role_menu` rm on ur.role_id = rm.role_id
        Left join `sys_menu` m on m.id = rm.menu_id
        where
        user_id = #{userId}
        and r.status = 0
        and m.status = 0
    </select>
</mapper>
相关推荐
长臂人猿7 天前
SpringSecurity构建登录模块
登录·token·springsecurity
Jack_abu14 天前
责任链模式在spring security过滤器链中的应用
java·责任链模式·springsecurity
诗水人间17 天前
前后端分离,解决vue+axios跨域和proxyTable不生效等问题
前端·javascript·vue.js·springboot·springsecurity·跨域·cros
柯南二号25 天前
SpringSecurity 鉴权认证入门讲解
认证·鉴权·springsecurity
NiNg_1_2341 个月前
SpringSecurity入门
后端·spring·springboot·springsecurity
北巷!!1 个月前
SpringSecurity源码中核心类
源码·springsecurity
ghx123456ghx2 个月前
springsecurity使用
springsecurity
小马爱打代码2 个月前
SpringSecurity框架核心组件详解
springsecurity
沿途欣赏i3 个月前
SpringSecurity剖析
springsecurity