SpringSecurity页面授权与登录验证实现(内存取值与数据库取值)

下面我将详细讲解“SpringSecurity页面授权与登录验证实现(内存取值与数据库取值)”的完整攻略。

一、概述

在开发Web应用程序时,安全性一直是非常重要的一环。Spring Security是Spring Framework所提供的一个强大的安全性框架,能够帮助我们很容易实现认证和授权功能。本文将介绍SpringSecurity页面授权与登录验证实现(内存取值与数据库取值)。

二、SpringSecurity登录验证实现

2.1 内存取值

SpringSecurity提供了一个很强大的内存验证功能,可以通过配置文件进行用户的认证和授权。接下来,我们将学习如何通过SpringSecurity实现基于内存的登录验证。

2.1.1 引入依赖

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>5.4.2</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>5.4.2</version>
</dependency>

2.1.2 配置SpringSecurity

<http use-expressions="true">
  <intercept-url pattern="/login" access="permitAll" />
  <intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
  <form-login login-page="/login" default-target-url="/welcome"
        authentication-failure-url="/login?error" />
  <logout logout-success-url="/login?logout" />
</http>
<authentication-manager>
  <authentication-provider>
    <user-service>
      <user name="admin" password="{noop}admin" authorities="ROLE_ADMIN" />
      <user name="user" password="{noop}user" authorities="ROLE_USER" />
    </user-service>
  </authentication-provider>
</authentication-manager>

这里我们配置了两个用户,admin和user,对应的密码分别是admin和user。同时分配了不同的角色,admin拥有ROLE_ADMIN角色、user拥有ROLE_USER角色。

2.1.3 编写登录页面

<form action="/login" method="post">
  <label for="username">Username:</label>
  <input type="text" id="username" name="username" />
  <br />
  <label for="password">Password:</label>
  <input type="password" id="password" name="password" />
  <br />
  <input type="submit" value="Sign In" />
</form>

2.1.4 编写安全配置类

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .anyRequest().authenticated()
        .and()
      .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/index")
        .permitAll()
        .and()
      .logout()
        .permitAll();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
      .inMemoryAuthentication()
        .withUser("admin").password("{noop}admin").roles("ADMIN")
        .and()
        .withUser("user").password("{noop}user").roles("USER");
  }
}

最后,我们启动Web应用程序,并访问http://localhost:8080/login,输入上述两种用户信息分别登录,可以看到根据角色的不同,用户被分配到了不同的页面上。

2.2 数据库取值

与内存取值相比,数据库取值是一种更高级的方法。在这种情况下,我们不再使用配置文件中的用户信息,而是将用户信息存储在数据库中。接下来,我们将学习如何将存储在数据库中的用户信息用于SpringSecurity的登录验证。

2.2.1 引入依赖

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>5.4.2</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>5.4.2</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-data</artifactId>
  <version>5.4.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.13</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-dbcp</artifactId>
    <version>${tomcat-dbcp.version}</version>
</dependency>

2.2.2 创建数据库表

我们可以创建一个名为users的表,用于存储用户名、密码和角色信息。SQL语句如下:

CREATE TABLE users(
   username VARCHAR(20),
   password VARCHAR(100),
   enabled TINYINT(1),
   PRIMARY KEY (username)
) ENGINE=InnoDB CHARSET=utf8;

CREATE TABLE authorities (
  username VARCHAR(50) NOT NULL,
  authority VARCHAR(50) NOT NULL,
  CONSTRAINT fk_authorities_users FOREIGN KEY(username) REFERENCES users(username)
)ENGINE=InnoDB CHARSET=utf8;

2.2.3 定义User类

创建一个User类来描述从数据库中检索的用户信息。

public class User implements UserDetails {

  private String username;
  private String password;
  private boolean enabled;

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    Set<GrantedAuthority> authorities = new HashSet<>();
    // 在这里实现查询用户权限代码,将查询出的权限添加到authorities中
    return authorities;
  }

  @Override
  public String getPassword() {
    return password;
  }

  @Override
  public String getUsername() {
    return username;
  }

  @Override
  public boolean isAccountNonExpired() {
    return true;
  }

  @Override
  public boolean isAccountNonLocked() {
    return true;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @Override
  public boolean isEnabled() {
    return enabled;
  }

  // setters 和 getters
}

2.2.4 定义UserDetailsService实现类

在 Spring Security 中,用户详细信息将由 UserDetailsService 负责提供。我们需要定义一个UserDetailsService实现类,用于从数据库中获取用户信息。

@Service
public class MyUserDetailsService implements UserDetailsService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    List<User> userList = jdbcTemplate.query(
      "SELECT * FROM users WHERE username = ?",
      new Object[]{username},
      (rs, rowNum) -> {
        User user = new User();
        user.setUsername(rs.getString("username"));
        user.setPassword(rs.getString("password"));
        user.setEnabled(true);
        return user;
      }
    );
    if (userList.isEmpty()) {
      throw new UsernameNotFoundException("User not found with username: " + username);
    }
    List<GrantedAuthority> authorities = new ArrayList<>();
    jdbcTemplate.query(
        "SELECT * FROM authorities WHERE username = ?",
        new Object[]{username},
        (rs, rowNum) -> {
          authorities.add(new SimpleGrantedAuthority(rs.getString("authority")));
          return null;
        });
    userList.get(0).setAuthorities(authorities);
    return userList.get(0);
  }
}

2.2.5 配置SpringSecurity

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private DataSource dataSource;
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
          .authorizeRequests()
              .antMatchers("/login", "/login-error").permitAll()
              .antMatchers("/admin/**").hasRole("ADMIN")
              .anyRequest().authenticated()
              .and()
          .formLogin()
              .loginPage("/login")
              .failureUrl("/login-error")
              .defaultSuccessUrl("/index")
              .and()
          .logout()
              .logoutSuccessUrl("/");
    }

    @Bean
    public JdbcUserDetailsManager jdbcUserDetailsManager() throws Exception {
      JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
      jdbcUserDetailsManager.setDataSource(dataSource);
      String encodedPassword = passwordEncoder().encode("123456");
      User user = new User("user", encodedPassword, true, Arrays.asList(new SimpleGrantedAuthority("USER")));
      User admin = new User("admin", encodedPassword, true, Arrays.asList(new SimpleGrantedAuthority("USER"), new SimpleGrantedAuthority("ADMIN")));
      jdbcUserDetailsManager.createUser(user);
      jdbcUserDetailsManager.createUser(admin);
      return jdbcUserDetailsManager;
    }
}

2.2.6 编写登录页面

页面与内存取值时的登录页面相同。

2.2.7 配置数据源

# 数据库配置
spring.datasource.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

2.2.8 完整示例

我们还可以通过完整的示例代码来加深了解:

https://github.com/delulin/spring-security-jdbc

三、SpringSecurity页面授权实现

3.1 引入依赖

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>5.4.2</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>5.4.2</version>
</dependency>

3.2 页面授权配置

在SpringSecurity中,我们可以通过配置角色来指定哪些用户有权限访问某些资源。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .antMatchers("/user/**").hasAnyRole("ADMIN", "USER")
        .and()
      .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/index")
        .permitAll()
        .and()
      .logout()
        .permitAll();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
      .inMemoryAuthentication()
        .withUser("admin").password("{noop}admin").roles("ADMIN")
        .and()
        .withUser("user").password("{noop}user").roles("USER");
  }
}

这里,我们配置了两个角色,ROLE_ADMIN和ROLE_USER。可以看到,通过.antMatchers()方法,我们为/admin/指定了权限为ROLE_ADMIN,为/user/指定了权限为ROLE_ADMIN和ROLE_USER。

3.3 完整示例

我们还可以通过完整的示例代码来加深了解:

https://github.com/delulin/spring-security-demo

四、总结

本文介绍了SpringSecurity如何实现页面授权和登录验证,分别介绍了基于内存和基于数据库的两种实现方法。通过了解SpringSecurity的相关配置和使用方法,我们可以在实际应用当中更好地使用和掌握SpringSecurity,从而保障我们Web应用程序的安全性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity页面授权与登录验证实现(内存取值与数据库取值) - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • 详解java如何正确使用volatile

    如何正确使用volatile 什么是volatile 在Java中,volatile是一种非常特殊的关键字。它用来表示一个变量是易变的,即它可能由于线程间的可见性导致不同线程读到不同的值。当我们声明一个变量为volatile时,Java会保证这个变量的内存可见性和线程安全性。 为什么使用volatile 因为当多个线程访问共享状态时,可能会出现一些意料不到的…

    Java 2023年5月26日
    00
  • Eclipse环境下如何配置Tomcat(把项目部署到Tomcat服务器上)

    下面是Eclipse环境下如何配置Tomcat的完整攻略,包括把项目部署到Tomcat服务器上的过程。 配置Eclipse环境 下载安装Eclipse 首先需要下载安装Eclipse IDE,可以去官网下载最新版Eclipse并进行安装。 下载安装Tomcat 进入Tomcat官网下载最新版本的Tomcat,并进行安装。 在Eclipse中安装插件 打开Ec…

    Java 2023年5月19日
    00
  • Java实现解析.xlsb文件的示例代码

    Java实现解析.xlsb文件的示例代码 什么是.xlsb文件格式 .xlsb文件格式是Excel二进制工作簿(Excel Binary Workbook)的缩写,它是一种二进制格式的电子表格文件。与其他的Excel文件格式相比,.xlsb文件具有更高的性能和更小的文件大小。然而,由于其二进制格式的特性,直接解析.xlsb文件需要一些特殊的技巧和工具。 示例…

    Java 2023年5月19日
    00
  • Java常用字符串方法小结

    Java常用字符串方法小结 字符串是Java中常用的数据类型之一,处理字符串的方法也是很多的。在本文中,笔者将会对Java中常用的字符串方法进行小结和总结,供读者参考。 获取字符串长度 获取字符串长度是常见的字符串操作。在Java中,可以调用length()方法获取字符串的长度。 示例代码: String str = "hello world!&q…

    Java 2023年5月26日
    00
  • Spring Security 实现用户名密码登录流程源码详解

    让我来详细讲解一下“Spring Security 实现用户名密码登录流程源码详解”的完整攻略。 一、说明 Spring Security 是一个基于 Spring 的安全框架,可以提供完整的安全性解决方案,包括认证、授权、攻击防护等方面的功能。 在本攻略中,我们将深入了解 Spring Security 如何实现基于用户名密码的登录流程,并分析其源码实现细…

    Java 2023年6月3日
    00
  • Spring Boot整合Kafka教程详解

    Spring Boot整合Kafka教程详解 近年来,Kafka 成为了备受关注和喜爱的消息系统,凭借其高吞吐量、低延迟的特性,成为了大型系统中消息传递和处理的首选工具。本文讲解如何在 Spring Boot 项目中整合 Kafka。 1. 添加 Maven 依赖 在 pom.xml 文件中添加以下依赖: <dependencies> <d…

    Java 2023年6月2日
    00
  • java中set接口使用方法详解

    Java中Set接口使用方法详解 Set接口是Java集合框架中提供的一种数据结构,它的特点是不允许有重复的元素,同时也没有顺序关系。在Java中,我们可以通过HashSet、TreeSet、LinkedHashSet等类来实现Set接口。 HashSet HashSet基于散列表实现,具有快速的添加、删除和查找元素的能力。 创建HashSet 创建一个空的…

    Java 2023年5月26日
    00
  • java FastJson的简单用法

    Java FastJson 的简单用法 FastJson 是一个 JSON 解析库,它可以将 Java 对象序列化为 JSON 数据,也可以将 JSON 数据反序列化为 Java 对象。FastJson 的使用非常简单,下面就介绍一下 Java FastJson 的简单用法。 FastJson 的引入 在使用 FastJson 之前,需要先引入 FastJs…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部