1.认证
密码校验用户
密码加密存储
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
- 我们没有这个配置,默认明文存储, {id}password;
- 实现这个,就变成加密存储: 加盐值 + 明文随机生成一段密文;
- 将返回UserDetails对象中的密码,与输入的密码进行校验
登录接口
- 在SpringSecurity放行登录接口,
- 定义AuthenticationManager @bean
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/user/login").anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
PS:就我们研究框架, 有些值,需要我们利用断点调试,层层拨开来进行获取。
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;
@Override
public ResponseResult login(UserDTO userDTO) {
// AuthenticationManager authenticationManager 进行认证
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword());
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
// 如果认证通过、给出对应提示
if(Objects.isNull(authenticate)){
throw new RuntimeException("登录失败");
}
// 认证通过使用userid生成jwt
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userId = loginUser.getUser().getId().toString();
String token = JwtUtil.createJWT(userId);
HashMap<String, String> map = new HashMap<>();
map.put("token",token);
// 把完整用户信息存入redis
redisCache.setCacheObject("login:"+userId,loginUser);
return new ResponseResult(200,"登录成功",map);
}
}
认证过滤器
我觉得下面配置,是配合前端适用的;
- 登录、请求等..页面,前端路由拦截器之类不需要拦截(没有token),那么页面相关请求,jwt过滤器是不需要拦截的。
- 首页等页面,需要token,那么必须是登录之后,拥有token,才能访问吧?访问页面,会携带token发送请求,访问资源。
@Component
public class JwtFilter extends OncePerRequestFilter {
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//获取token
String token = request.getHeader("Authorization").substring(6);
if(StringUtils.isEmpty(token)){
filterChain.doFilter(request,response);
return;
}
//解析token
String userid;
try {
Claims claims = JwtUtil.parseJWT(token);
userid = claims.getSubject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("token非法");
}
//从redis中获取用户信息
String redisKey = "login:" + userid;
LoginUser loginUser = redisCache.getCacheObject(redisKey);
if(Objects.isNull(loginUser)){
throw new RuntimeException("用户未登录");
}
//存入SecurityContextHolder
//TODO 获取权限信息封装到Authentication中
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行
filterChain.doFilter(request, response);
}
}
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/user/login").anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
//把token校验过滤器添加到过滤器链中,就是在 UsernamePasswordAuthenticationFilter之前
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}