maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
实现加密 向ioc容器中注入bCryptPasswordEncoder 这个加密是一个单向的加密 通过hash算法+盐+密匙 对密码加密
@Configuration
public class passwordCrypt {
//向ioc容器中注册 pring Security的一个加密类BCryptPasswordEncoder
@Bean("bCryptPasswordEncoder")
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
在需要调用加密方法的类中注入
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
//在注册时进行对密码加密然后存数据库中
bCryptPasswordEncoder.encode(frontAdmin.getaPassword())
//在登录时候进行密码匹配
//第一个为用户登录时输入的密码,第二个是数据库中查到的密码
bCryptPasswordEncoder.matches(aPassword, admin.getAPassword())
SecurityConfig配置实例
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 授权规则配置
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭csrf防护
http.csrf().disable();
// 解决跨域问题
http.cors();
http.authorizeRequests()
//登录路径放行
.antMatchers("/login").permitAll()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll();
}
}
springsecurit认证和授权
在前端点击登录时首先会被AbstractAuthenticationProcessingFilter这个过滤器拦截到然后执行他的doFilter方法,然后会执行该过滤器中的attemptAuthentication方法 这个方法被其子类
UsernamePasswordAuthenticationFilter重写 会调用该子类中的attemptAuthentication方法进行验证登录 将提交的密码和账号 进行封装成 UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
//是否认证成功
setAuthenticated(false);
}
把这个token交给AuthenticationManager进行认证 接下来调用的时ProviderManager中的实现AuthenticationManager重写的方法authenticate 前端提交表单数据后端验证使用的是DaoAuthenticationProvider中的父类中AbstractUserDetailsAuthenticationProvider的authenticate方法进行验证,方法中有 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); 调用DaoAuthenticationProvider重写的方法
protected final UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
try {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
catch (UsernameNotFoundException ex) {
mitigateAgainstTimingAttack(authentication);
throw ex;
}
catch (InternalAuthenticationServiceException ex) {
throw ex;
}
catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
此时我们就要实现UserDetailsService 自定义实现登录逻辑,返回UserDetails对象,UserDetails也是一个接口 我们也要实现它,完成重写实体类 .如果成功返回Authentication授权对象 2. 然后AbstractAuthenticationProcessingFilter的doFilter方法就会调用认证成功的successfulAuthentication(request, response, chain, authResult);方法然后SecurityContextHolder.getContext().setAuthentication(authResult);将授权信息方到security的上下文中。认证失败会有相应的失败的处理器
3.授权 是在BasicAuthenticationFilter过滤器中拦截的 重写doFilterInternal方法
在这里先获取授权信息然后将授权信息交给SecurityContextHolder.getContext().setAuthentication(authResult);将授权信息方到security的上下文中
//获取该用户的权限信息
public List<GrantedAuthority> getUserAuthority(Long userId){
// 角色(ROLE_admin)、菜单操作权限 sys:user:list
String authority = sysUserService.getUserAuthorityInfo(userId); // ROLE_admin,ROLE_normal,sys:user:list,....
return AuthorityUtils.commaSeparatedStringToAuthorityList(authority);
}
//这个是认证成功的token
UsernamePasswordAuthenticationToken authRequest
= new UsernamePasswordAuthenticationToken(username,jwt, List<GrantedAuthority> );
//将授权信息方到security的上下文中
SecurityContextHolder.getContext().setAuthentication(authRequest);
//认证
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}
细粒度的权限验证
要想使用springSecurity注解进行权限验证,
1.在启动类上进行 使用注解先要开启注解功能
@EnableGlobalMethodSecurity(securedEnabled=true)
(1)在控制器上添加注解 ,判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“
@Secured
({
"ROLE_normal"
,
"ROLE_admin"
})
(2)@PreAuthorize
:注解适合进入方法前的权限验证,