Spring Boot 2.x实战82 - Spring Security 6 - 一个完整的Spring Security实战演示(基于用户、角色、权限)

2 Spring Security实战

在这一节我们讲演示一个基于用户、角色、权限的更为实用的例子;一个用户有一个或多个角色,每个角色有一个或多个的权限。

新建应用,信息如下:

Group:top.wisely

Artifact:learning-spring-security-in-battle

Dependencies:Spring SecuritySpring Web StarterSpring Data JPAMySQL DriverLombok

build.gradle文件中的依赖如下:

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-security'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   compileOnly 'org.projectlombok:lombok'
   runtimeOnly 'mysql:mysql-connector-java'
   annotationProcessor 'org.projectlombok:lombok'
   //...
}

删除上一个应用的数据库SYS_USER表,在application.yml中连接数据库:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/first_db?useSSL=false
    username: root
    password: zzzzzz
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

用户、角色、权限的实体分别是SysUserSysRoleSysAuthority

我们也看权限的实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysAuthority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name; //权限名称

    private String value; //权限值

    public SysAuthority(String name, String value) {
        this.name = name;
        this.value = value;
    }
}

角色的实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysRole {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(targetEntity = SysAuthority.class)
    private Set<SysAuthority> authorities; // 角色和权限是多对多的关系

    public SysRole(String name, Set<SysAuthority> authorities) {
        this.name = name;
        this.authorities = authorities;
    }
}

用户的实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysUser implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    @NotNull
    private String username;

    private String password;

    private String realName;

    private Boolean enable;

    @ManyToMany(targetEntity = SysRole.class, fetch = FetchType.EAGER)
    private Set<SysRole> roles; //用户和角色是多对多的关系

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new HashSet<>();
        roles.forEach(role -> {
            role.getAuthorities().forEach(authority -> {
                authorities.add(new SimpleGrantedAuthority(authority.getValue()));
            });
        });
        return authorities; //获取当前用户的角色集合,通过角色集合获得当前用户的权限集合。
    }

    public SysUser(String username, String password, String realName, Boolean enable, Set<SysRole> roles) {
        this.username = username;
        this.password = password;
        this.realName = realName;
        this.enable = enable;
        this.roles = roles;
    }
	// 省略其它接口方法
}

三个Repository分别为:

public interface SysUserRepository extends JpaRepository<SysUser, Long> {
    Optional<SysUser> findByUsername(String username);
}
public interface SysRoleRepository extends JpaRepository<SysRole, Long> {
}
public interface SysAuthorityRepository extends JpaRepository<SysAuthority, Long> {
}

安全的配置:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint());
    }

    @Bean
    AuthenticationEntryPoint authenticationEntryPoint(){
        BasicAuthenticationEntryPoint authenticationEntryPoint = new BasicAuthenticationEntryPoint();
        authenticationEntryPoint.setRealmName("wisely");
        return authenticationEntryPoint;
    }

    @Bean
    UserDetailsService userDetailsService(SysUserRepository sysUserRepository){
        return new CusotmUserDetailsService(sysUserRepository); //源码和上节相同
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

演示权限的控制器方法:

    @GetMapping("/userCan1")
    @PreAuthorize("hasAuthority('userCan1')") //当前用户拥有的Authorities是否包含userCan1
    public Map<String, Object> userCan1(@AuthenticationPrincipal SysUser sysUser){
        return getReturnMap(sysUser,"userCan1");
    }

    @GetMapping("/userCan2")
    @PreAuthorize("hasAuthority('userCan2')")//当前用户拥有的Authorities是否包含userCan2
    public Map<String, Object> userCan2(@AuthenticationPrincipal SysUser sysUser){
        return getReturnMap(sysUser,"userCan2");

    }

    @GetMapping("/adminCan1")
    @PreAuthorize("hasAuthority('adminCan1')")//当前用户拥有的Authorities是否包含adminCan1
    public Map<String, Object> adminCan1(@AuthenticationPrincipal SysUser sysUser){
        return getReturnMap(sysUser,"adminCan1");
    }

    @GetMapping("/adminCan2")
    @PreAuthorize("hasAuthority('adminCan2')")//当前用户拥有的Authorities是否包含adminCan2
    public Map<String, Object> adminCan2(@AuthenticationPrincipal SysUser sysUser){
        return getReturnMap(sysUser,"adminCan2");
    }

    private Map<String, Object> getReturnMap(SysUser sysUser, String currentAuthority) {
        Map<String, Object> map = new HashMap<>();
        map.put("user-authorities" , sysUser.getAuthorities()); //
        map.put("current-authority", "userCan1");
        return map;
    }
    
}

我们通过CommandLineRunner初始化系统的所有权限、角色和用户,第二次运行系统的时候要记得注释掉这些代码:

@SpringBootApplication
public class LearningSpringSecurityInBattleApplication {

   public static void main(String[] args) {
      SpringApplication.run(LearningSpringSecurityInBattleApplication.class, args);
   }

   @Bean
   CommandLineRunner init(SysUserRepository sysUserRepository,
                     SysRoleRepository sysRoleRepository,
                     SysAuthorityRepository sysAuthorityRepository,
                     PasswordEncoder passwordEncoder){
      return args -> {
         SysAuthority authority1 = sysAuthorityRepository.save(new SysAuthority("userCan1","userCan1"));
         SysAuthority authority2 = sysAuthorityRepository.save(new SysAuthority("userCan2","userCan2"));
         SysAuthority authority3 = sysAuthorityRepository.save(new SysAuthority("adminCan1","adminCan1"));
         SysAuthority authority4 = sysAuthorityRepository.save(new SysAuthority("adminCan2","adminCan2"));

         SysRole role1 = sysRoleRepository.save(new SysRole("普通用户",
               Stream.of(authority1,authority2).collect(Collectors.toSet())));
         SysRole role2 = sysRoleRepository.save(new SysRole("管理员",
               Stream.of(authority1,authority2,authority3,authority4).collect(Collectors.toSet())));

         SysUser user1 = sysUserRepository.save(new SysUser("wyf",
               passwordEncoder.encode("111111"),
               "wangyunfei",
               true,
               Stream.of(role1).collect(Collectors.toSet())));

         SysUser user2 = sysUserRepository.save(new SysUser("admin",
               passwordEncoder.encode("admin"),
               "administrator",
               true,
               Stream.of(role2).collect(Collectors.toSet())));

      };
   }

}

普通用户角色的用户wyf,可以访问userCan1userCan2管理员角色的用户admin,可访问userCan1userCan2adminCan1adminCan2

访问http://localhost:8080/userCan1,两个用户均能访问。
在这里插入图片描述
访问http://localhost:8080/adminCan1,只有管理员角色用户才能访问,管理员角色包含adminCan1权限。
在这里插入图片描述

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html
在这里插入图片描述

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和批处理(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/106936379