Spring Boot整合Spring Security(九)简单的鉴权

阅前提示

此文章基于Spring Security 6.0

权限信息在UserDetails中的体现

在该系列之前的篇章中,已经介绍过,UserDetais中GrantedAuthority部分是用来存放权限信息的
上篇,基于数据库的用户认证中说到,在项目中创建了2个用户,在创建的时候,明明只填写了USER,ADMIN,在数据库中却存储着ROLE_ADMIN,ROLE_USER。
代码回顾

UserDetails user = User.builder()
     .username("user")
     .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
     .roles("USER")
     .build();

这是因为,在创建用户权限信息的时候使用了User.builder().role()这个方法。这个方法的具体代码如下

		public UserBuilder roles(String... roles) {
            List<GrantedAuthority> authorities = new ArrayList(roles.length);
            String[] var3 = roles;
            int var4 = roles.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String role = var3[var5];
                Assert.isTrue(!role.startsWith("ROLE_"), () -> {
                    return role + " cannot start with ROLE_ (it is automatically added)";
                });
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
            }

            return this.authorities((Collection)authorities);
        }

意思是创建用户角色信息时,不能以“ROLE_”开头,接着它会自动把“ROLE_”加到角色信息上去
那么如何使用不带“ROLE_”开头的权限信息呢,以及为什么要带“ROLE_”呢

        UserDetails leader = User.builder()
                .username("leader")
                .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
                .authorities("LEADER")
                .build();

使用User.builder().authorities()方法构造User类时,会自动将填写的内容转化成Collection<? extends GrantedAuthority>类,放入UserDetails中的相应部分
重启项目后再来看一遍数据库表信息
在这里插入图片描述
这样,在创建用户时,authorities中填写什么,数据库中就怎么存储

为什么要添加ROLE_前缀

RBAC模型

RBAC,基于角色的权限访问控制(Role-Based Access Control)
RBAC的核心在于用户只和角色关联,而角色代表对了权限,是一系列权限的集合。
RBAC三要素:

  • 用户:系统中所有的账户
  • 角色:一系列权限的集合(如:管理员,开发者,审计管理员等)
  • 权限:菜单,按钮,数据的增删改查等详细权限。

在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系同样也存在继承关系防止越权。

举个例子

假如公司里有老板,领导,员工3种职位,老板什么都能干,拥有最高权限,领导除了不能看老板在其他地方还有什么资产外,什么都能看,员工只能对他的日报,周报,月报增删查改。有一天,公司老板发现有个领导想查他资产,开除了,换了个领导。这时候需要把系统中关于这个领导的权限全部删除,再建立一个新的领导档案。如果没有“领导”角色分配给他,就得把所有他所能拥有的权限一个一个分给他,负责管理系统的员工想骂人。
所以角色权限的集合,将角色分配个用户后,等于将一系列的权限分配给用户了,不用一个一个分配,不仅麻烦还容易出错

鉴权配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorizeHttpRequests ->
                        authorizeHttpRequests
                                .requestMatchers("/favicon.ico","/csrf","/captcha","/").permitAll()
                                .requestMatchers("/admin/**").hasRole("ADMIN")
                                .requestMatchers("/leader/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasAuthority('LEADER')"))
//                                .requestMatchers("/leader/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasAuthority("LEADER")))
                                .anyRequest().denyAll()
                )
        return http.build();
    }
}

回顾一下之前篇章,当时配置http.authorizeHttpRequests的内容的时候,是为了将登录界面及登录接口和一些静态资源在认证之前放行,不至于因为没有登录被拦截。现在配置的是关于权限信息的(以上代码中,注释部分跟上面一行相同效果)。当访问requestMatchers匹配的路径时,访问者如果没有相应的角色信息,是会被拒绝访问的403。当然与hasRole()对应的,还有hasAnyAuthority()用来验证粒度更细的权限

AuthorizationManagers.anyOf()拥有其中任何一个权限即可。对应WebExpressionAuthorizationManager中使用or
AuthorizationManagers.allOf()拥有其中所有权限才可。对应WebExpressionAuthorizationManager中使用and

  • permitAll 允许所有
  • denyAll 拒绝所有
  • hasRole 校验角色
  • hasAuthority 校验权限
  • authenticated 需要认证
  • fullyAuthenticated 需要完全认证
  • rememberMe 记住我(已经登录过)
  • anonymous 匿名(不允许登录访问)
  • access 底层调用,所有的鉴权其实都是调用了这个方法

一些小吐槽

其实我觉得这个篇章应该放到这个系列的开头几篇文章中,但是本来就不擅长写文章,更不擅长设计文章的结构,就想到平时使用的顺序该怎么样就怎么写。本来想写一个使用攻略系列的,结果又是攻略又是源码分析的,我自己都不知道在记录些什么东西了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值