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日

相关文章

  • 关于并发编程与线程安全的思考与实践

    作者:京东健康 张娜 一、并发编程的意义与挑战 并发编程的意义是充分的利用处理器的每一个核,以达到最高的处理性能,可以让程序运行的更快。而处理器也为了提高计算速率,作出了一系列优化,比如: 1、硬件升级:为平衡CPU 内高速存储器和内存之间数量级的速率差,提升整体性能,引入了多级高速缓存的传统硬件内存架构来解决,带来的问题是,数据同时存在于高速缓存和主内存中…

    Java 2023年5月9日
    00
  • Java 在游戏中探索数组二维数组

    Java 在游戏中探索数组二维数组 什么是数组和二维数组 在 Java 编程中,数组就是一个固定大小的容器,可以用来存储一组相同类型的数据。如果我们需要将一组数据存储起来,而且这组数据的类型相同且数量确定,那么数组就是最好的选择。 二维数组是由多个一维数组组成的。它可以看做是一个表格,每个一维数组就相当于表格的一行,而每个元素就相当于表格中的一个单元格。二维…

    Java 2023年5月26日
    00
  • Java数组传递及可变参数操作实例详解

    Java数组传递及可变参数操作实例详解 在Java中,数组有时需要被作为参数传递给一个方法或者函数,然后再在该方法或函数中进行使用。另外,有时候我们也需要在参数列表中使用可变参数。本文将详细讲解Java数组传递及可变参数的操作实例。 Java数组传递 Java中的数组是一种引用类型,而非基本数据类型。这意味着,传递数组时,我们实际上传递的是数组引用的副本,而…

    Java 2023年5月26日
    00
  • mysql connector 执行 select 和 shardingshpere-proxy 的处理过程

    use java mysql connector // fake mysql select code // … datasource init Connection conn = datasource.getConnection(); PreparedStatement pst = conn.prepareStatement(“select id, ta…

    Java 2023年4月18日
    00
  • Spring之ShutDown Hook死锁现象解读

    Spring之ShutDown Hook死锁现象解读 什么是ShutDown Hook死锁 在Spring应用程序正常关闭的过程中,ShutDown Hook是一个非常有用的工具。ShutDown Hook是Java进程中的一段代码块,用于在应用程序关闭时处理一些清理工作。ShutDown Hook是Spring框架中提供的一种线程,它可以在Spring应用…

    Java 2023年5月31日
    00
  • Springboot项目快速实现拦截器功能

    针对“Springboot项目快速实现拦截器功能”,我可以提供以下完整攻略: 1. 引入依赖 在pom.xml中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web…

    Java 2023年5月19日
    00
  • 记录一个使用Spring Data JPA设置默认值的问题

    下面是详细的讲解过程: 1. 背景 在使用Spring Data JPA进行开发中,我们可能会遇到需要给某个字段设置默认值的情况,但很多人可能不知道如何实现。本文将介绍如何使用Spring Data JPA设置默认值,并提供两个示例。 2. 解决方案 Spring Data JPA提供了多种设置默认值的方式,包括使用实体类构造方法、使用@PrePersist…

    Java 2023年6月1日
    00
  • java返回json请求中文变成问号的问题及解决

    下面是详细讲解“Java返回JSON请求中文变成问号的问题及解决”的完整攻略: 问题描述 在使用Java后端向前端返回JSON格式数据时,如果数据中包含中文字符,有时候会出现中文字符被转换成问号的情况,造成数据不可读。这个问题通常出现在字符编码设置不正确的情况下。 解决方法 方法一:设置字符编码 设置正确的字符编码可以解决这个问题。在Java中设置字符编码有…

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