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日

相关文章

  • SpringBoot整合Hibernate Validator实现参数验证功能

    下面我将详细讲解“SpringBoot整合Hibernate Validator实现参数验证功能”的完整攻略,过程中将包含两条示例。 什么是Hibernate Validator Hibernate Validator是一款Java Bean验证框架,它提供了一套丰富的注解,使用这些注解可以很方便地实现对Java Bean字段的验证。在一些Web开发中,我们…

    Java 2023年5月20日
    00
  • java 数据库连接与增删改查操作实例详解

    Java 数据库连接与增删改查操作实例详解 数据库连接 在 Java 中,可以通过使用 JDBC 驱动程序来实现与数据库的连接。步骤如下:1. 加载驱动程序2. 建立数据库连接3. 关闭数据库连接 加载驱动程序 Java 中的 DriverManager 类提供了一个用于加载 JDBC 驱动程序的 registerDriver() 方法。驱动程序可以通过 C…

    Java 2023年5月19日
    00
  • 使用java NIO及高速缓冲区写入文件过程解析

    使用Java NIO及高速缓冲区写入文件可以提高文件写入的效率,下面我来为大家详细讲解该过程的完整攻略。 1. Java NIO简介 Java NIO(New IO)是Java SE 1.4版本引入的非阻塞I/O API,它比原来的I/O API(现在称为IO)更快、更灵活、更可扩展。NIO由以下几个核心组件组成: Buffer(缓冲区):NIO中的所有I/…

    Java 2023年5月19日
    00
  • 如何保证Java线程安全性?

    为了保障Java程序的正确运行,我们需要确信Java线程的安全性。在Java语言中,可以使用以下几种方式来保证线程安全性: 使用同步块(Synchronized Block)或者同步方法(Synchronized Method)来保护共享变量。将多个线程对共享变量的访问限制为同一时间内只能有一个线程进行操作,从而保障数据的正确性和线程安全性。示例代码如下: …

    Java 2023年5月11日
    00
  • SpringMVC ModelAndView的用法使用详解

    SpringMVC ModelAndView的用法使用详解 在 SpringMVC 中,ModelAndView 是一个常用的类,用于封装控制器处理请求后的返回结果。它可以同时包含模型数据和视图信息,方便控制器将处理结果返回给客户端。本文将详细讲解 SpringMVC ModelAndView 的用法,包括如何创建 ModelAndView 对象、如何设置模…

    Java 2023年5月18日
    00
  • Jaspersoft Studio添加mysql数据库配置步骤

    下面我来详细讲解“Jaspersoft Studio添加mysql数据库配置步骤”的完整攻略,过程中我将会包含两条示例说明。 1. 下载MySQL JDBC驱动程序 Jaspersoft Studio需要通过JDBC连接到MySQL数据库,因此需要下载MySQL JDBC驱动程序。在MySQL官网下载页面(https://dev.mysql.com/down…

    Java 2023年6月16日
    00
  • Java中的这些骚操作你不能不知道!!!

    Java中的这些骚操作你不能不知道!!! 本篇文章将为你介绍Java中的一些高级操作和技巧,帮助你更好地理解和使用Java。 1. 位操作符 Java提供了许多位操作符,如左移运算符(<<)、右移运算符(>>)和按位与运算符(&)等。这些运算符可以帮助我们对二进制数做一些处理,使程序更加高效。 例如,我们可以使用左移运算符来快…

    Java 2023年5月30日
    00
  • 浅谈web服务器项目中request请求和response的相关响应处理

    关于“浅谈web服务器项目中request请求和response的相关响应处理”,我们可以从以下几个方面展开: 一、HTTP request请求的相关处理 HTTP请求通常包括方法、URL、HTTP版本、请求头和请求体等部分,服务器在接收到请求后需要根据请求的不同部分进行处理。 方法(method) 请求方法指定了客户端希望服务器执行的操作。常用的方法有GE…

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