精通 Spring Boot 系列 15

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 精通 Spring Boot 系列 15

阅读全文,约 16 分钟

这是江帅帅的第022篇原创

Spring Security 的持久化案例

当我们在企业中处理登录认证和授权的时候,需要把信息存储到数据库中,我们的用户名和密码通过验证,然后认证和授权,最重要的还需要做加密处理。

结合 JPA 的案例

1)编辑 pom.xml 文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.nx</groupId>
    <artifactId>springbootdata</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/>
    </parent>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
 
   <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
 
  <dependencies>
 
      <!-- 添加spring-boot-starter-web模块依赖 -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
 
      <!-- 添加spring-boot-starter-thymeleaf模块依赖 -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
 
    <!-- 添加spring-boot-starter-security 依赖 -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
 
    <!-- 添加mysql数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
 
    <!-- 添加spring-boot-starter-data-jpa模块 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
 
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
2)编辑 application.properties 文件
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=1234
logging.level.org.springframework.security=trace
spring.thymeleaf.cache=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
3)创建 User 和 Role 持久化类

先看 Role 类。

@Entity
@Table(name="tb_role")
public class Role implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private Long id;
    @Column(name="authority")
    private String authority;
 
    public Role() {
        super();
    }   
}

再看 User 类。

@Entity
@Table(name="tb_user")
public class User implements Serializable{
 
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private Long id;
    private String loginName;
    private String username;
    private String password;
 
    @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
    @JoinTable(name="tb_user_role",
    joinColumns={@JoinColumn(name="user_id")},
    inverseJoinColumns={@JoinColumn(name="role_id")})
    private List<Role> roles;
 
    // setXxx 和 getXxx 方法
}
4)创建 UserRepository 数据访问接口
public interface UserRepository extends JpaRepository<User, Long>{
    // 根据登录名查询出用户
    User findByLoginName(String loginName);
}
5)创建 UserService 服务类
// 我们在这里需要实现 UserDetailsService 接口
// 因为配置的相关参数需要是 UserDetailsService 类型的数据
@Service
public class UserService implements UserDetailsService{
 
    // 注入持久层接口 UserRepository
    @Autowired
    UserRepository userRepository;
 
    // 重写 UserDetailsService 接口中的 loadUserByUsername 方法,通过该方法查询到对应的用户
    // 其中定义了一些可以获取用户名、密码、权限等与认证相关的信息的方法。
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 
        User User = userRepository.findByLoginName(username);
        if (User == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        // GrantedAuthority 对象代表赋予给当前用户的权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 获得当前用户权限集合
        List<Role> roles = User.getRoles();
        for (Role role : roles) {
            // 将关联对象 Role 的 authority 属性保存为用户的认证权限
            authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
        }
 
        return new User(User.getUsername(), User.getPassword(), authorities);
    }
}
6)创建 AppSecurityConfigurer  认证处理类
// 需要继承自WebSecurityConfigurerAdapter来完成,相关配置重写对应方法即可。 
@Configuration
public class AppSecurityConfigurer extends WebSecurityConfigurerAdapter{
 
    // 注入用户服务类
    @Autowired
    private UserService userService;
 
    // 注入加密接口
    @Autowired
    private PasswordEncoder passwordEncoder;
 
    // 注入用户认证接口
    @Autowired
    private AuthenticationProvider authenticationProvider;
 
    // 注入认证处理成功类,验证用户成功后处理不同用户跳转到不同的页面
    @Autowired
    AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;
 
    // BCryptPasswordEncoder 用来创建密码的加密程序,避免明文存储密码到数据库
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
    @Bean
    public AuthenticationProvider authenticationProvider() {
        // 创建DaoAuthenticationProvider对象
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 不要隐藏"用户未找到"的异常
        provider.setHideUserNotFoundExceptions(false);
        // 通过重写configure方法添加自定义的认证方式。
        provider.setUserDetailsService(userService);
        // 设置密码加密程序认证
        provider.setPasswordEncoder(passwordEncoder);
        return provider;
    }
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置认证方式。
        auth.authenticationProvider(authenticationProvider);
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
 
        http.authorizeRequests()
 
        .antMatchers("/login","/css/**","/js/**","/img/*").permitAll() 
        .antMatchers("/", "/home").hasRole("USER")
        .antMatchers("/admin/**").hasAnyRole("ADMIN", "DBA")
        .anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login").successHandler(appAuthenticationSuccessHandler)
        .usernameParameter("loginName").passwordParameter("password")
        .and()
        .logout().permitAll()
        .and()
        .exceptionHandling().accessDeniedPage("/accessDenied");
    }
}

上面主要是展示代码,呈现的 HTML 页面和数据,大家可以自行添加。


目录
相关文章
|
4月前
|
Java Spring
spring boot 中WebMvcConfigurer相关使用总结
spring boot 中WebMvcConfigurer相关使用总结
69 3
|
4月前
|
存储 安全 Java
Spring Boot
【7月更文挑战第16天】Spring Boot
29 1
|
6月前
|
安全 Java 应用服务中间件
精通 Spring Boot 系列 03
精通 Spring Boot 系列 03
39 0
|
6月前
|
存储 Java Maven
精通 Spring Boot 系列 01
精通 Spring Boot 系列 01
25 0
|
6月前
|
Java 数据库连接 数据库
精通 Spring Boot 系列 13
精通 Spring Boot 系列 13
41 0
|
6月前
|
Java 数据库 Spring
精通 Spring Boot 系列 12
精通 Spring Boot 系列 12
42 0
|
6月前
|
Java Spring
精通 Spring Boot 系列 09
精通 Spring Boot 系列 09
42 0
|
存储 缓存 算法
Spring Boot 中的 ConcurrentMapCacheManager
Spring Boot 中的 ConcurrentMapCacheManager
|
Java Spring
Spring Boot 3.0
Spring Boot 3.0
648 0
|
XML Java 应用服务中间件
欢迎光临Spring Boot时代(一)1
欢迎光临Spring Boot时代(一)1
欢迎光临Spring Boot时代(一)1