下面我将详细讲解“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技术站