目录

1. 简介

1.1 身份认证

1.2 授权

2. 实战案例

2.1 依赖管理

2.2 自定义用户

2.3 自定义授权规则

2.4 自定义用户查询

2.5 自定义登录页面


1. 简介

Spring Security 是一个提供身份验证、授权和防护常见攻击的框架。它为确保命令式和反应式应用程序的安全提供一流的支持,是确保基于 Spring 的应用程序安全的事实标准。

1.1 身份认证

身份验证是我们验证试图访问特定资源者身份的方式。验证用户身份的常用方法是要求用户输入用户名和密码。一旦进行了身份验证,我们就知道了用户的身份,并可以执行授权。Spring Security 提供对用户身份验证的内置支持。以下是Spring Security支持的认证机制:

  • 用户名 & 密码

  • OpenID Connect 的 OAuth 2.0 登录和非标准 OAuth 2.0 登录

  • SAML 2.0 登录

  • 中央认证服务器 (CAS)

  • 如何在会话过期后记住用户

  •  JAAS 身份验证

  • OpenID 身份验证(不要与 OpenID Connect 混淆)

  • SiteMinder 或 Java EE 安全性等外部机制进行身份验证

  • X509 认证

我们工作中用的最多的也就是"用户名 & 密码" 与 "OAuth2";所以,本篇文章就以用户名&密码讲解。

1.2 授权

无论你选择以何种方式进行身份验证--是使用 Spring Security 提供的机制和提供商,还是与容器或其他非 Spring Security 身份验证机构集成--你都会发现授权服务可以以一致而简单的方式在你的应用程序中使用。

2. 实战案例

2.1 依赖管理

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

当环境中引入上面的依赖后,默认情况会对所有的请求都进行拦截,同时启动服务时会输出随机密码,而用户则默认是"user"。

Spring Security基础教程:从入门到实战-LMLPHP

2.2 自定义用户

在配置文件中配置用户名密码等信息。

spring:  security:    user:      name: pack      password: 123456

当你在配置文件中做了如上配置后,控制台将不会输出随机生成的密码。

2.3 自定义授权规则

在上面的示例中,默认情况Spring Security对所有的请求进行拦截,有些时候我们希望只对某些请求进行拦截、静态资源自动放行,这时候就需要我们自定义授权规则。在Spring Security中是通过配置SecurityFilterChain Bean对象进行授权规则的配置。

@Bean
public SecurityFilterChain apiSecurity(HttpSecurity httpSecurity) throws Exception {
  // 关闭csrf
  httpSecurity.csrf(csrf -> csrf.disable()) ;
  // 拦截所有以/api/开头的请求
  httpSecurity.authorizeHttpRequests().antMatchers("/api/**").authenticated() ;
  // 放行所有的静态资源(其实,如果你这里就配置了一个/api/**,那么下面的都不用配置,因为只会拦截/api/)
  httpSecurity.authorizeHttpRequests().antMatchers("*.js", "*.css", "*.html").permitAll() ;
  // 而这配置,则会通过表单形式进行用户名&密码的登录授权操作。默认提供了简单的登录界面
  httpSecurity.formLogin(withDefaults()) ;
  return httpSecurity.build() ;
}

默认登录页

Spring Security基础教程:从入门到实战-LMLPHP

针对不同的请求配置不同的权限(角色)。

// 访问/api/前缀的请求用户必须具备MGR角色
httpSecurity.authorizeHttpRequests().antMatchers("/api/**").hasAnyRole("MGR") ;
// /admin/前缀的请求必须具备SUPER角色
httpSecurity.authorizeHttpRequests().antMatchers("/admin/**").hasAnyRole("SUPER") ;

配置文件中配置角色

spring:
  security:
    user:
      roles:
      - SUPER

当你不具备对应的角色,你将看到如下错误

Spring Security基础教程:从入门到实战-LMLPHP

2.4 自定义用户查询

在上面的示例中,都是基于配置文件进行用户的配置角色的设置,都是静态的信息,而实际工作中,都是需要从数据库中进行查询的。关于数据库的操作,我这里使用的spring data jpa。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

实体User定义

@Entity
@Table(name = "p_user")
public class User implements UserDetails {

  private static final long serialVersionUID = 1L ;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id ;
  private String username ;
  private String password ;
  private String email ;
  private String address ;
  private Integer age ;

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    // 这里为了简单起见,就直接固定了
    return Arrays.asList(
          new SimpleGrantedAuthority("ROLE_MGR"),
          new SimpleGrantedAuthority("ROLE_NORMAL")
        );
  }
  @Override
  public String getPassword() {
    return this.password ;
  }
  @Override
  public String getUsername() {
    return this.username ;
  }
  // 下面几个方法你,也应该根据你实际系统用户的状态设置
  @Override
  public boolean isAccountNonExpired() {
    return true ;
  }
  @Override
  public boolean isAccountNonLocked() {
    return true ;
  }
  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }
  @Override
  public boolean isEnabled() {
    return true ;
  }
  // getter, setter
}

Spring Security中如果你需要基于数据库的验证,那么你还需要提供如下的配置Bean

@Bean
UserDetailsService packUserDetailsService(UserRepository userRepository) {
  return new UserDetailsService() {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      User user = userRepository.findByUsername(username) ;
      return user ;
    }
  } ;
}

@Bean
PasswordEncoder packPasswordEncoder() {
  // 生产环境中你不应该使用该种PasswordEncoder。
  return NoOpPasswordEncoder.getInstance() ;
}

UserRepository接口

public interface UserRepository extends JpaRepository<User, Long> {

  // 我这是由于有很多的重复数据,所以。。。
  @Query(value = "select * from p_user u where u.username = ?1 limit 1", nativeQuery = true)
  User findByUsername(String username) ;

}

通过以上的配置就完成了与数据库的结合登录验证。

2.5 自定义登录页面

默认情况下的,登录页面你肯定不会应用到生产环境中,都会自定义登录页面。在如下目录新增自定义的登录页面

Spring Security基础教程:从入门到实战-LMLPHP

配置

@Bean
SecurityFilterChain apiSecurity(HttpSecurity httpSecurity) throws Exception {
  // ...
  httpSecurity.formLogin(login -> login.loginPage("/login.html").loginProcessingUrl("/login")) ;
  return httpSecurity.build() ;
}

Spring Security基础教程:从入门到实战-LMLPHP

以上是本篇文章的全部内容,如对你有帮助就请作者吃个棒棒糖🍭。

完毕!!!

推荐文章

使用RabbitMQ消息队列和Redis缓存优化Spring Boot秒杀功能

Spring Boot + 支付宝支付:一站式集成指南

​​​​​​​Spring Boot整合Elasticsearch

Spring Boot与RabbitMQ整合:实现高可用消息队列服务

Spring Boot携手OAuth2.0,轻松实现微信扫码登录!

快速上手Spring Boot与Mybatis Plus集成

《布隆过滤器:原理、应用与使用方法深度解析》

《深度解析:Redis缓存穿透、击穿与雪崩的区别及应对策略》

Spring框架九大核心功能全面揭秘(一)

权威解析Spring框架九大核心功能(续篇):专业深度,不容错过

Spring框架九大核心功能全面解读(三):探寻功能之巅

揭秘Spring Boot中@Transactional注解失效的七大坑点与修复之道

RabbitMQ Spring Boot 配置与使用指南

Spring Boot集成RabbitMQ实现消息队列生产者与消费者

05-07 12:34