文章目录
1. SpringSecurity简介
Spring Security基于Spring框架,提供了一套Web应用安全性的完整解决方案。
关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,web应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是Spring Security的重要核心功能。
(1)用户认证指的是:验证某个用户是否为系统的合法主体,一般要求用户提供用户名和密码,系统通过校验用户名和密码完成认证的过程。通俗的说就是系统认为用户是否能登录
(2)用户授权指的是:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。一般来说,系统会为不同的用户分配不同的角色,而每个角色对应一系列的权限。通俗的说就是系统判断用户是否有权限去做某些事情。
2. SpringSecurity基本原理
本质是一个过滤器链
2.1 三个重要的过滤器
重点有三个过滤器:
(1) FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤器链的最底部;
(2) ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常;
(3) UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中用户名、密码。
2.2 UserDetailsService说明
什么也不配置的情况下,账号密码是SpringSecurity定义生成的,但在实际项目中,账号密码都是从DB中获取的,所以我们可以通过实现UserDetailsService接口,来自定义控制认证逻辑。
如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。
public interface UserDetailsService {
/**
* Locates the user based on the username. In the actual implementation, the search
* may possibly be case sensitive, or case insensitive depending on how the
* implementation instance is configured. In this case, the <code>UserDetails</code>
* object that comes back may have a username that is of a different case than what
* was actually requested..
* @param username the username identifying the user whose data is required.
* @return a fully populated user record (never <code>null</code>)
* @throws UsernameNotFoundException if the user could not be found or the user has no
* GrantedAuthority
*/
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
3. 入门实践
3.1 依赖引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.2 账号密码配置
有三种方式配置账号、密码
(1)application.yml配置文件配置
spring:
security:
user:
name: test
password: test123
(2)配置类实现
package com.qs.springsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author QuS
* @date 2021/11/8 15:53
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodePass = passwordEncoder.encode("xiaoming123");
auth.inMemoryAuthentication().withUser("xiaoming").password(encodePass).roles("admin");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
(3)自定义逻辑控制认证。
- 设计数据表、创建db。省略
- 设计po实体类、mapper层。省略
- 制作登录实现类。即实现UserDetailsService
注:可以在此处给用户登录主体赋予相关权限,这些权限可以来源于数据库,此处作为练习写死
给用户设置角色时,需要"ROLE_"开头
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> grantedAuthorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("read,user");
UserPO userPO = userMapper.selectOne(new QueryWrapper<UserPO>().eq("username", username));
if (userPO == null) {
throw new UsernameNotFoundException("username not exist!");
}
return new User(username, new BCryptPasswordEncoder().encode(userPO.getPassword()), grantedAuthorityList);
}
}
- 编写配置类
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource; //数据源注入
/**
* 配置操作数据库对象,免密登录使用
*
* @return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
//用户退出
http.logout()
.logoutUrl("/login/loginOut")
.logoutSuccessUrl("/myLogin.html")
.permitAll();
//配置没有访问权限(403)时,自定义的跳转页面
http.exceptionHandling().accessDeniedPage("/unAuth.html");
http.formLogin() //表单登录
.loginPage("/myLogin.html") //登录页面配置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/success.html") //登录成功之后,跳转路径
.usernameParameter("myLoginUsername") //获取指定登录用户名参数
.passwordParameter("myLoginPassword") //获取指定登录密码参数
.permitAll()
.and()
.authorizeRequests() //认证配置
.antMatchers("/", "/login/**")
.permitAll() //用户可以任意访问
.antMatchers("/security/**").hasAnyAuthority("read", "write") //需要用户带有read或者write的权限
.antMatchers("/user/**").hasRole("user") //需要用户拥有ROLE_user的角色
.anyRequest() //所有请求
.authenticated() //需要身份认证,才可以访问
.and()
.csrf().disable() //关闭csrf防护
.rememberMe().tokenRepository(persistentTokenRepository()) //免密登录
.tokenValiditySeconds(60)
.userDetailsService(userDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}