springboot集成security(鉴权)

Posted 364.99°

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot集成security(鉴权)相关的知识,希望对你有一定的参考价值。


本文承接上一章节内容:springboot集成security(认证)

上一章节: https://blog.csdn.net/m0_54355172/article/details/128239128

1. 授予静态资源访问权限

因为我的演示案例涉及到多个页面,所以先说一下如何给静态资源授予访问权限。

不过首先,我先来讲一下 springboot中无法访问到静态资源的问题的处理方案,这个不涉及security。

1. springboot访问不到静态资源的处理方案

一般,我们会把 .html 和其对应的 静态资源(.css.js.png)分开放置:

  • .html 放到 /resources/templates/
  • 静态资源放到 /resources/static/**

可是,我们会发现,这样放置,在启动项目的时候,根本访问不到静态资源,其解决方案如下:

  • 修改启动类:

    @MapperScan("com.chenjy.security_demo.mapper")
    @SpringBootApplication
    public class SecurityDemoApplication extends WebMvcConfigurationSupport 
    
        public static void main(String[] args) 
            SpringApplication.run(SecurityDemoApplication.class, args);
        
    
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) 
            registry.addResourceHandler("/css/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/css/");
            super.addResourceHandlers(registry);
        
    
    
    • extends WebMvcConfigurationSupport,重写 addResourceHandlers
    • 在方法中增加对 /css 路径的映射。
  • 修改html:

    <html lang="en" xmlns:th="https://www.thymeleaf.org">
    <head>
      <base th:href="@/">
      <meta charset="UTF-8">
      <title>登录</title>
      <link rel="stylesheet" href="../../static/css/login.css" th:href="@/css/login.css"/>
    </head>
    
    • html 标签的 xmlns:th=“https://www.thymeleaf.org” 引用不能缺少
    • head 标签里增加 <base th:href=“@/”> 配置
    • 修改 link 标签 <link rel=“stylesheet” href=“…/…/static/css/login.css” th:href=“@/css/login.css”/>

2. 授权访问静态资源

经过上述配置之后,我们如果不使用 security 的话,就能访问到静态资源了,但是当我们使用了 security,那么我们会发现,又访问不到静态资源了。

这是因为,我们没有权限访问静态资源,所以,我们需要授权访问静态资源。

.antMatchers("/**/*.css") // 从根目录开始,授予所有目录下的所有 .css 文件的可访问权限
.permitAll()

2. 权限授予的方法

授权都是基于路径匹配

方法说明
permitAll免登陆访问
一般描述静态资源,css、js、jpg
anonymous登录后不可访问
登录页面和登录请求
authenticated登录后可访问
denyAll任意用户任意状态都不可访问
fullyAuthenticated完整登录才可访问
收支
rememberMe记住我,一段时间内访问免登陆

上面所有方法的底层都是 access ,可以实现任何权限授予逻辑,基于权限表达式的权限授予方法。

权限表达式:

  • 定值表达式
    access(“permitAll”) 等同于 permitAll()
  • 动态表达式

3. 权限管理

1. 基于角色的权限管理(role)

role: 权限

user: 用户

role_user:映射

1. 数据库查询

根据用户名查询权限。

  • mapper

        <select id="getRoleByName" parameterType="string" resultType="string">
            select
                r.authority
            from
                role r,
                role_user ru
            where
                r.id = ru.rid
              and ru.uid = (
                select
                    rid
                from
                    role_user
                where
                    uid = ( select id from user where name = #name ))
        </select>
    
    String getRoleByName(String name);
    
  • service

    String getRoleByName(String name);
    
        @Override
        public String getRoleByName(String name) 
            return userMapper.getRoleByName(name);
        
    

2. UserDetailsServiceImpl权限获取

从数据库获取对应角色的权限,并将权限封装到 UserDetails 中返回。

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
        com.chenjy.security_demo.dto.User user = userService.getUserByName(username);
        if (user == null) 
            throw  new UsernameNotFoundException("用户名错误");
        
        // 用户登录成功之后,查询用户的权限集合,包括角色和权限
        // security 严格要求:角色名的前缀必须是ROLE_,在代码中拼接
        // 角色和权限是平等的,都是权限
        String auth = "ROLE_" + userService.getRoleByName(username);
        System.out.println(username + "的权限是:" + auth);

        // 匹配用户密码
        // createAuthorityList可以装入一个字符串,也可以多个字符串,也可以直接装入一个字符串数组
        User res = new User(username, user.getPassword(), AuthorityUtils.createAuthorityList(auth));
        return res;
    

loadUserByUsername 中, security 会等待用户登录成功之后,再去查询用户权限。

注意: security 严格要求:角色名的前缀必须是 ROLE_,但不建议在数据库中直接存入前缀,建议在代码中拼接字符串。

启动项目,登录,查看控制台输出:

3. 配置访问权限

前端代码: https://blog.csdn.net/m0_54355172/article/details/128247732

事先已经写好了两个页面:resource.html——对应接口:/resource、free.html——对应接口:/free

现在需要配置其访问权限:/resource——只有权限为 all 的用户才可以访问,/free——所有用户都可以访问。

.antMatchers("/resource")
.hasRole("all")
.antMatchers("/free")
.hasAnyRole("all", "sim")

演示一下效果:

hasRole(all) 具备 all 权限才能访问匹配到的路径。
hasAnyRole(“all”, “sim”) 具备 allsim 中任意一个权限就可以访问匹配到的路径。

2. 基于资源的权限管理(authority)

相比于 基于角色的权限管理基于资源的权限管理 更加细粒度。

hasAuthority(“read,write”)

hasAnyAuthority(“read,write”, “read”)

3. 基于客户端ip的权限管理(IPAddress)

.antMatchers("/free")
.hasIpAddress("127.0.0.1")

注意:ip规则访问要求完整匹配,所以不能填写 localhost 作为ip。

  • 按照上述配置,localhost 就不能访问 /free

  • 通过打印访问的主机ip,可知道 localhost 的ip 为 0:0:0:0:0:0:0:1

    request.getRemoteHost()
    

    修改配置:

    .hasIpAddress("0:0:0:0:0:0:0:1")
    

    但是可以发现,localhost 依旧访问不到资源

    但是 127.0.0.1 就可以访问。

小结: 别用 localhost

未完待续…

以上是关于springboot集成security(鉴权)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 接口认证鉴权入门实践指南

SpringBoot配置属性-Security

前后端分离项目中 springboot 集成 shiro 实现权限控制

spring security oauth2认证中心 集成zuul网关的代码分析

Spring Security应用详解(集成SpringBoot)

Spring Security应用详解(集成SpringBoot)