SpringBoot集成SpringSecurity(入门级)

简介: 目录Springboot集成SpringSecurity Demo 快速上手-初步入门: 创建单用户单角色的安全控制多用户多角色的实现思路 每个身份都使用一个登录实体类...

目录

目录创建于2017-12-18


Springboot集成SpringSecurity

Demo

快速上手-初步入门:

创建单用户单角色的安全控制

  • 添加依赖
   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
      @Autowired
      private ReaderRepository readerRepository;
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
            .antMatchers("/").access("hasRole('READER')")//要求登陆者进入根目录必须具有 READER 的角色
            .antMatchers("/**").permitAll()//其他页面开放了权限
          .and()
          .formLogin()
            .loginPage("/login")//登录表单的路径
            .failureUrl("/login?error=true");
      }
      @Override
      protected void configure(
                  AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new UserDetailsService() {//定义自定义的UserDetailService
            @Override
            public UserDetails loadUserByUsername(String username)
                throws UsernameNotFoundException {
              UserDetails userDetails = readerRepository.findOne(username);
              if (userDetails != null) {
                return userDetails;
              }
              throw new UsernameNotFoundException("User '" + username + "' not found.");
            }
          });
      }
    }

Repository类

   public interface ReaderRepository extends JpaRepository<Reader, String> {}
    //登录实体类
    @Entity
    public class Reader implements UserDetails {
      private static final long serialVersionUID = 1L;
      @Id
      private String username;
      private String fullname;
      private String password;
      //省略setget
      //授予READER权限
      @Override
      public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_READER"));
      }
      //不过期
      @Override
      public boolean isAccountNonExpired() { return true;}
      //不加锁
      @Override
      public boolean isAccountNonLocked() {return true;}
      //不禁用
      @Override
      public boolean isCredentialsNonExpired() {return true;}
      //可用
      @Override
      public boolean isEnabled() { return true;}
    }

多用户多角色的实现思路

  • 使用多个实体类(实现了UserDetails接口),一个权限类,再一个多对多连接,就得到了多用户,多权限的控制
  • 在页面上加上角色的判断来控制数据显示,业务操作等功能

  • 根据书上案例代码,可以得出结论,用户表,角色表,用户角色关联表,用户表是可以多张的,角色公用一张即可,然后关联表也对应的多张,就能实现具体的业务需求

    • 例如:一个网上在线阅读书城,作家和读者以及编辑,网站后台管理员等角色的不同权限对应的页面甚至页面上细分的各个模块
  • Author Admin Reader 三个类
    继承了UserDetails接口的实体类的配置

    //配置多对多的关系,用户和角色(权限)之间的关系,是通用的改下属性名即可
    @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
    private List<AllRoles> roles ;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        List<AllRoles> roles = this.getRoles();
        for(AllRoles role:roles){
            auths.add(new SimpleGrantedAuthority(role.getRole_name()));
        }
        return auths;
    }
    // 登录的用户名,如果属性不是叫username,就要重写,返回应该的用户名属性就是了
    @Override
    public String getUsername() { return this.reader_name;}
    @Override
    public boolean isAccountNonExpired() {return true;}
    @Override
    public boolean isAccountNonLocked() {return true;}
    @Override
    public boolean isCredentialsNonExpired() {return true;}
    @Override
    public boolean isEnabled() {return true;}
每个身份都使用一个登录实体类
  • 然后使用不同的dao层查询,显然的实体类登录查询的效率及其低且不易扩展
  • 设置好spirng.jpa.hibernate.ddl-auto=update
  • 第一次运行还会有没有实体对应的表这样的提示,说明了他正在根据多对多映射创建实体表,也体现了这个多种用户模式下需要实体等量的连接表
  • 所以这个是要查询多张表了
    • (除非UserDetailService接口的loadUserByUsername能收到表类别的参数)
    • 也可以考虑使用一个字符串,然后用特殊字符把类型放进去,然后正则取出来
    • 登录页面就需要自定义一个函数进行拼接(或者使用校验来拼接?)
另一种思路:
  • 使用一个登录用户表(序列id,用户名,密码,用户编码(对应多张表))
  • 角色表(序列id,用户编码,角色)
    这样的话扩展就只要加表,使用同一个主键生成策略就可以了

  • 思考:

    • 其实这个安全框架使用的是角色控制,而不是权限控制,目前的了解,达不到Oracle那样的权限加角色控制

实现细节

关于注解的几种使用方式

@Secured

  • 这是基于Spring特定的注解

@RolesAllowed

  • JSR-250的@RolesAllowed Java标准定义的注解,与上面的注解是差不多的
  • 但是都是有局限性,只能判断请求是否有权限,不能进行更多的自定义判断

SpringSecurity3.0 开始提供了 SpEL表达式

需要先配置这个配置类,后面的注解才会生效

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{}
  • @PreAuthorize 方法调用前,基于表达式的计算结果来限制方法的访问
  • @PostAuthorize 允许方法调用,如果表达式是false 抛出安全异常
  • @PostFilter 允许方法调用,按照表达式来过滤方法的结果
  • @PreFilter 允许方法调用,必须进入方法前过滤输入值

  • 方法调用前验证权限,示例:

    • @PreAuthorize("hasRole('ROLE_ADMIN')") 只允许该权限的用户访问
    • 方法入参user,限定读者用户的text长度小于140,或者是作家用户无限制
    • @PreAuthorize("(hasRole('ROLE_READER') and #user.text.length()<=140 ) or hasRole('ROLE_AUTHOR')")
  • 方法调用之后验证权限,示例;
    • @PostAuthorize("returnObject.spitter.username == principal.username")
    • public Spittle getSpittleById(long id){}
    • 保护方法,只有当返回的对象就是当前登录的用户时,才返回,不然抛出安全异常
      以上是保护方法的调用,但是有时候保护的是数据的输入输出:
  • 过滤方法的输入输出
    • 事后对方法的返回值进行过滤
      • @PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
      • @PostFilter("hasRole('ROLE_ADMIN') || filterObject.user.username == principal.name")
      • public List<User> getUsers(){}
      • 该示例就是限制了如果是管理员可以获取到所有数据,普通用户只能看到自己
      • 但是这种实现是不好的,只是一个例子,只获取自己,重载方法加个id参数就好了,上面的实现,把数据全拿出来再判断,性能上。。。
    • 事先对方法的参数进行过滤
      • @PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
      • @PreFilter("hasRole('ROLE_ADMIN') || targetObject.user.username == principal.name")
      • public void deleteUsers(){List<User> users}
      • 示例实现了传入一个集合,要删除的用户,但是当前用户只能删除自己,管理员才能删除集合里所有的用户
    • 定义许可计算器
      • @PreFilter("hasPermission(targetObject,'delete')") 用户是否有权限删除目标对象?
      • 使用了自定义的计算器类来实现这个判断,表达式简洁,但是自定义类不好写
      • 实现PermissionEvaluator接口,新建hasPermission方法,功能就是判断是否有权限,其实就是对比目标对象是不是当前用户
      • 创建好类后,重载GlobalMethodSecurityConfiguration配置类的createExpressionHalder方法,注册进去
      • DefaultMethodSecurityExperssionHandler ex = new De...();
      • ex.setPermissionEvaluator(new 自定义类);
      • return ex;

保护方法应用

  • @Secured 注解限制方法调用
目录
相关文章
|
3月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
1月前
|
XML Java API
Spring Boot集成MinIO
本文介绍了如何在Spring Boot项目中集成MinIO,一个高性能的分布式对象存储服务。主要步骤包括:引入MinIO依赖、配置MinIO属性、创建MinIO配置类和服务类、使用服务类实现文件上传和下载功能,以及运行应用进行测试。通过这些步骤,可以轻松地在项目中使用MinIO的对象存储功能。
|
2月前
|
消息中间件 Java Kafka
什么是Apache Kafka?如何将其与Spring Boot集成?
什么是Apache Kafka?如何将其与Spring Boot集成?
75 5
|
2月前
|
消息中间件 Java Kafka
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
59 1
|
2月前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
52 2
|
2月前
|
XML Java 数据库连接
SpringBoot集成Flowable:打造强大的工作流管理系统
在企业级应用开发中,工作流管理是一个核心组件,它能够帮助我们定义、执行和管理业务流程。Flowable是一个开源的工作流和业务流程管理(BPM)平台,它提供了强大的工作流引擎和建模工具。结合SpringBoot,我们可以快速构建一个高效、灵活的工作流管理系统。本文将探讨如何将Flowable集成到SpringBoot应用中,并展示其强大的功能。
379 1
|
3月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
97 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
3月前
|
安全 Java 关系型数据库
springboot整合springsecurity,从数据库中认证
本文介绍了如何在SpringBoot应用中整合Spring Security,并从数据库中进行用户认证的完整步骤,包括依赖配置、数据库表创建、用户实体和仓库接口、用户详情服务类、安全配置类、控制器类以及数据库初始化器的实现。
251 3
springboot整合springsecurity,从数据库中认证
|
2月前
|
消息中间件 监控 Java
您是否已集成 Spring Boot 与 ActiveMQ?
您是否已集成 Spring Boot 与 ActiveMQ?
61 0
|
2月前
|
JSON Java API
springboot集成ElasticSearch使用completion实现补全功能
springboot集成ElasticSearch使用completion实现补全功能
49 1