精通 Spring Boot 系列 15

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 精通 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 页面和数据,大家可以自行添加。


目录
相关文章
|
8月前
|
搜索推荐 Java 索引
Spring Boot中的ElasticsearchRepository
Spring Boot中的ElasticsearchRepository
|
8月前
|
Java 数据格式 Docker
Spring Boot
Spring Boot 入门
131 0
|
12天前
|
Java Spring
精通 Spring Boot 系列 09
精通 Spring Boot 系列 09
23 0
|
12天前
|
存储 安全 Java
精通 Spring Boot 系列 14
精通 Spring Boot 系列 14
10 0
|
12天前
|
Java Spring
精通 Spring Boot 系列 11
精通 Spring Boot 系列 11
23 0
|
12天前
|
Java 数据库 Spring
精通 Spring Boot 系列 12
精通 Spring Boot 系列 12
24 0
|
12天前
|
前端开发 Java 文件存储
精通 Spring Boot 系列 06
精通 Spring Boot 系列 06
28 0
|
10月前
|
Java Spring
Spring Boot 3.0
Spring Boot 3.0
574 0
|
11月前
|
存储 JSON 安全
Spring Boot 安全
1.概述 在后端来说,安全主要就是控制用户访问,让对应权限的用户能访问到对应的资源,主要是两点: 认证 授权 认证,确定是谁。 授权,核实权限。 每个安全框架其实都是为了实现这两点。 目前常用的实现方式有如下几种: token JWT oauth spring security 前三种是理念,最后一种是开箱即食的框架。 2.token 2.1.理论 token ,也叫“令牌”,是验证用户身份的凭证。token的组成具有随意性,能标识用户身份即可。
99 0
|
XML Java 应用服务中间件
欢迎光临Spring Boot时代(一)1
欢迎光临Spring Boot时代(一)1
欢迎光临Spring Boot时代(一)1