Spring 全家桶之 Spring Security(二)

2022-08-19 15:25:56 浏览数 (1)

什么是认证?什么事授权?

认证(Authentication):

  认证的主要作用是识别当前用户是否是系统中的有效用户

授权(Authorization):

  授权的主要作用是给登录系统的用户的角色授予该角色角色所能访问的菜单列表或者能操作的功能

RBAC是什么

RBAC概念

  RBAC既Role Base Access Control 给予角色的访问控制,在RBAC的概念中,权限与角色相关联,用户拥有特定的角色从而可以自动获取这些角色的权限,这样会简化权限的管理,基本思想就是对系统的各种操作权限不应该直接赋给用户,而是在用户集合和权限集合之间建立一个角色集合,每一种角色都对应一组响应的权限,一旦用户被分配了适当的角色后,该用户就拥有了角色的所有操作权限,创建用户时只需要给用户分配角色,就可以获取一组权限,设计好角色对应的权限集合,就能很好的简化权限的管理。RBAC中用户是属于角色的,角色拥有权限的集合,用户属于某个角色,该用户就拥有角色对应的权限,如后台管理系统中普通用户只能查看数据,管理员可以修改数据。

RBAC表设计

  基于RBAC的数据库表设计,至少含有四个表,用户表包含用户名密码是否启用等字段,角色表包含角色名称角色表述等字段,角色和用户是多对多的关系,需要一个中间表来关联用户和角色的关系,角色和用户关系表包含用户ID和角色ID两个字段,还有一个权限表,表示角色由哪些权限,权限可以由uri来表示

Spring Security中的认证接口和类

1)UserDetails: interface,用户信息接口 Methods: boolean isAccountNonExpired(); 账号是否过期 boolean isAccountNonLocked();账号是否锁定 boolean isCredentialsNonExpired();证书是否过期 boolean isEnabled();账号是否启用 Collection<? extends GrantedAuthority> getAuthorities(); 权限集合 Implements Class: User

常用方法:User.builds(),User.withUsername().password().roles() 可以自定义类实现UserDetails接口,作为系统中的用户类。

2)UserDetailsService:interface,用户信息Service接口 获取用户信息,得到UserDetails对象,需要自定义类实现接口,从数据库中获取数据, 需要实现方法UserDetails loadUserByUsername(String var1) :根据用户名称,获取用 户信息(用户名称,密码,角色结合,是否可用,是否锁定等信息)

UserDetailsService接口的实现类有 I:InMemoryUserDetailsManager:在内存中维护用户信息。使用方便,但是数据只保存在内存中,重启后数据丢失 II: JdbcUserDetailsManager: 用户信息存储在数据库中,使用Spring的JDBC Template操作数据,可以完成创建,更新,删除,判断是否存在等功能

InMemoryUserDetailsManager类的使用

1.新建一个maven项目并加入依赖

代码语言:javascript复制
<!--加入spring boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>

<!--指定依赖-->
<dependencies>
    <!--web开发相关依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--spring security-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

2.在config包中创建应用的配置类 1)创建密码的处理类对象 2)使用InMemoryUserDetailsManager创建用户

代码语言:javascript复制
@Configuration
public class ApplicationSecurityConfig {

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

    @Bean
    public UserDetailsService userDetailsService(){
        PasswordEncoder passwordEncoder = passwordEncoder();

        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        // 创建内存中用户,赋予ADMIN角色和USER角色
        manager.createUser(User.withUsername("admin")
                .password(passwordEncoder.encode("12345"))
                .roles("ADMIN","USER").build());

        manager.createUser(User.withUsername("thor")
                .password(passwordEncoder.encode("12345"))
                .roles("USER").build());

        return manager;
    }
}

3.在config包中创建WebSecurityCinfigurerAdapter

代码语言:javascript复制
@EnableWebSecurity
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.userDetailsService(userDetailsService);
    }
}

4.在controller包中创建Controller控制器

代码语言:javascript复制
@RestController
public class HelloSecurityController {

    @GetMapping("/hello")
    public String helloUserAndAdmin(){
        return "Hello Spring Security";
    }
}

5.创建SpringBoot应用启动类

代码语言:javascript复制
@SpringBootApplication
public class SecurityApplication {

    public static void main(String[] args) {

        SpringApplication.run(SecurityApplication.class,args);
    }
}

启动应用,浏览器地址输入http://localhost:8080 会自动跳转至http://localhost:8080/login

JdbcUserDetailsManager类使用

1.首先创建数据表,拷贝users.ddl文件,作简要修改

代码语言:javascript复制
create table users(username varchar(50) not null primary key,password varchar(500) not null,enabled boolean not null);
create table authorities (username varchar(50) not null,authority varchar(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

2.创建一个新的maven项目并添加依赖

代码语言:javascript复制
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.1.5.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.18</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

3.在application.properties中配置数据源

代码语言:javascript复制
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

4.在config包中创建配置类

代码语言:javascript复制
@Configuration
public class SecurityConfig {

    @Autowired
    private DataSource dataSource;

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

    @Bean // bean id为jdbcUserDetailsManager
    public UserDetailsService jdbcUserDetailsManager(){

        PasswordEncoder passwordEncoder = passwordEncoder();

        JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
        manager.createUser(User.withUsername("odin")
                .password(passwordEncoder.encode("12345"))
                .roles("ADMIN","MANAGER","USER")
                .build());

        manager.createUser(User.withUsername("thor")
                .password(passwordEncoder.encode("12345"))
                .roles("MANAGER","USER")
                .build());

        manager.createUser(User.withUsername("loki")
                .password(passwordEncoder.encode("12345"))
                .roles("USER")
                .build());

        return manager;

    }
}
代码语言:javascript复制
@EnableWebSecurity
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Resource //根据bean id导入
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.congfigure(http);
        http.userDetailsService(userDetailsService);
    }
}

5.创建SpringBoot应用启动类

代码语言:javascript复制
@SpringBootApplication
public class SecurityApplication {

    public static void main(String[] args) {

        SpringApplication.run(SecurityApplication.class,args);
    }
}

启动应用,浏览器地址输入http://localhost:8080 会自动跳转至http://localhost:8080/login 可以实现认证功能

0 人点赞