1.springsecurity底层实现为一条过滤器链。其实就是认证和授权
2.springsecurity自带一个登录页。对登录请求入手,替换掉自带的,对输入的账号密码进行验证。
3.定义一个配置类 继承 WebSecurityConfigurerAdapter
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*
* 配置策略
*
* @param httpSecurity
*
* @throws Exception
*/
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 由于使用的是JWT,我们这里不需要csrf
.csrf().disable()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
// 对于登录login 图标 静态资源允许匿名访问
.antMatchers("/login/**").anonymous()
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() //访问此地址不需要身份认证
// 对于以上 没有添加的 都需经过过滤器认证
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated().and().headers().frameOptions().disable();
}
}
4.自定义一个对象实现UserDetails(Security提供),接下来的认证过程需要用到
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
@Setter
@Getter
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SecurityUser implements UserDetails{
private Integer userId;
private String username;
private String password;
//用户权限
private Collection<? extends GrantedAuthority> authorities;
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
/**
* 返回分配给用户的角色列表
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* 账户是否未过期,过期无法验证
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
* @return
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
* @return
*/
@Override
public boolean isEnabled() {
return true;
}
}
5.定义账号密码登录业务 实现UserDetailsService接口,这里的SysUserService根据自己的用户实体类
@Slf4j
@Service("userDetailsService")
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private SysUserService sysUserService;
/**
*
* @Description: 账号密码登录业务
* @author: zhou
* @date: 2022年6月29日 下午4:39:10
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据登录用户名 从数据库中查询登录用户信息
SysUser user = sysUserService.loginByUserName(username);
if (user == null) {
log.info("登录用户:" + username + " 不存在.");
throw new RuntimeException("登录用户:" + username + " 不存在");
}
List<String> list = new ArrayList<String>(Arrays.asList("admin","test"));
List<SimpleGrantedAuthority> authorities = list.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
return new SecurityUser(user.getUserId(),username,user.getPassword(), authorities);
}
}
5.1 注意:返回用户权限一定不能为空或者null
5.2 这里获取到用户密码 是经过加密后的密码(数据库存的密码是加密后的),下面也会讲到
6.定义自己登录业务 的实现类
/**
* @Description: TODO(这里用一句话描述这个类的作用)
* @param:
* @return:
* @author: zhou
* @date: 2022年6月29日 下午8:33:54
*/
@Override
public String login(String username, String password) {
// 用户验证
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
//其实 就是执行 上面UserDetailServiceImpl的方法
if (authentication == null) {
throw new RuntimeException("登录失败");
}
// 存储认证信息
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成token
SecurityUser userDetail = (SecurityUser) authentication.getPrincipal();
return JWTUtils.generateToken(userDetail); //这个根据自己定义吧
}
7.在配置类中添加上自己的登录业务。让springSecurity 根据加密规则对原生登录进行加密再与数据库中密码比对。
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailServiceImpl userDetailsService;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}