3.SpringSecurity+登录功能+jwt校验过滤器+redis配置

打印 上一主题 下一主题

主题 555|帖子 555|积分 1665

SpringSecurity+登录功能+jwt校验过滤器+redis配置

一、思路分析

1.登录
  1. ①自定义登录接口  
  2.                         调用ProviderManager的方法进行认证 如果认证通过生成jwt
  3.                         把用户信息存入redis中
  4. ②自定义UserDetailsService
  5.                         在这个实现类中去查询数据库
  6. 注意配置passwordEncoder为BCryptPasswordEncoder
复制代码
2.校验:
  1. ①定义Jwt认证过滤器
  2.                         获取token
  3.                         解析token获取其中的userid
  4.                         从redis中获取用户信息
  5.                         存入SecurityContextHolder
复制代码
二、登录接口代码实现(第一次登陆获取jwt)

1.业务代码
  1.         @Autowired
  2.     private AuthenticationManager authenticationManager;
  3.     @Autowired
  4.     private RedisCache redisCache;
  5.         @Override
  6.     public ResponseResult login(User user) {
  7.         //1,使用springsecurity功能认证,把用户名密码存入令牌
  8.         UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
  9.         //2.1,默认使用UserDetailService去内存中找user用户,需要定义Impl实现类来重写查询方法,改成从数据库查询
  10.         //2.2,UserDetailServiceImpl从数据库查询出user返回到authenticate这里。具体查看a类
  11.         Authentication authenticate = authenticationManager.authenticate(authenticationToken);
  12.         //2.3,判断是否认证通过
  13.         if(Objects.isNull(authenticate)){
  14.             throw new RuntimeException("用户名或密码错误");
  15.         }
  16.         //3.1,获取userid 生成token
  17.         LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
  18.         String userId = loginUser.getUser().getId().toString();
  19.         //3.2,生成jwt
  20.         String jwt = JwtUtil.createJWT(userId);
  21.         //3.3,把用户信息存入redis
  22.         redisCache.setCacheObject("bloglogin:"+userId,loginUser);
  23.         //4.1,把token和userinfo封装 返回
  24.         //4.2,把User转换成UserInfoVo
  25.         UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class);
  26.         BlogUserLoginVo vo = new BlogUserLoginVo(jwt,userInfoVo);
  27.         return ResponseResult.okResult(vo);
  28.     }
复制代码
2.a类:UserDetailsServiceImpl
  1. @Service
  2. public class UserDetailsServiceImpl implements UserDetailsService {
  3.     @Autowired
  4.     private UserMapper userMapper;
  5.     @Override
  6.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  7.         //根据用户名查询用户信息
  8.         LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
  9.         queryWrapper.eq(User::getUserName,username);
  10.         User user = userMapper.selectOne(queryWrapper);
  11.         //判断是否查到用户  如果没查到抛出异常
  12.         if(Objects.isNull(user)){
  13.             throw new RuntimeException("用户不存在");
  14.         }
  15.         //返回用户信息
  16.         // TODO 查询权限信息封装
  17.         return new LoginUser(user);
  18.     }
  19. }
复制代码
3.SecurityConfig配置类
  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3.     @Bean
  4.     public PasswordEncoder passwordEncoder(){
  5.         return new BCryptPasswordEncoder();
  6.     }
  7.     @Override
  8.     protected void configure(HttpSecurity http) throws Exception {
  9.         http
  10.                 //关闭csrf
  11.                 .csrf().disable()
  12.                 //不通过Session获取SecurityContext
  13.                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  14.                 .and()
  15.                 .authorizeRequests()
  16.                 // 对于登录接口 允许匿名访问
  17.                 .antMatchers("/login").anonymous()
  18.                 // 除上面外的所有请求全部不需要认证即可访问
  19.                 .anyRequest().permitAll();
  20.         http.logout().disable();
  21.         //允许跨域
  22.         http.cors();
  23.     }
  24.     @Override
  25.     @Bean
  26.     public AuthenticationManager authenticationManagerBean() throws Exception {
  27.         return super.authenticationManagerBean();
  28.     }
  29. }
复制代码
三、登录校验过滤器代码实现(校验jwt)

1.登录校验过滤器
  1. @Component
  2. public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
  3.     @Autowired
  4.     private RedisCache redisCache;
  5.     @Override
  6.     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, IOException, ServletException {
  7.         //1,获取请求头中的token
  8.         String token = request.getHeader("token");
  9.         if(!StringUtils.hasText(token)){
  10.             //说明该接口不需要登录直接放行,如果是第一次登陆的话跳转到登陆去获取token
  11.             filterChain.doFilter(request, response);
  12.             return;
  13.         }
  14.         //2,解析获取userid
  15.         Claims claims = null;
  16.         try {
  17.             //String jwt = JwtUtil.createJWT(userId);jwt内容为id
  18.             claims = JwtUtil.parseJWT(token);
  19.         } catch (Exception e) {
  20.             e.printStackTrace();
  21.             //token超时  token非法
  22.             //响应告诉前端需要重新登录
  23.             ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
  24.             WebUtils.renderString(response, JSON.toJSONString(result));
  25.             return;
  26.         }
  27.         String userId = claims.getSubject();
  28.         //3,从redis中获取用户信息
  29.         LoginUser loginUser = redisCache.getCacheObject("bloglogin:" + userId);
  30.         //如果获取不到
  31.         if(Objects.isNull(loginUser)){
  32.             //说明登录过期  提示重新登录
  33.             ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
  34.             WebUtils.renderString(response, JSON.toJSONString(result));
  35.             return;
  36.         }
  37.         //4,存入SecurityContextHolder
  38.         UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null);
  39.         //UPToken令牌存入Security上下文的设置身份验证属性中,后面过滤器会从Security上下文这里获取用户信息
  40.         SecurityContextHolder.getContext().setAuthentication(authenticationToken);
  41.         filterChain.doFilter(request, response);
  42.     }
  43. }
复制代码
2.登录校验过滤器加入到过滤器组中
  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3.     @Override
  4.     @Bean
  5.     public AuthenticationManager authenticationManagerBean() throws Exception {
  6.         return super.authenticationManagerBean();
  7.     }
  8.         //1,注入登录校验过滤器
  9.     @Autowired
  10.     private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
  11.     @Override
  12.     protected void configure(HttpSecurity http) throws Exception {
  13.         http
  14.                 //关闭csrf
  15.                 .csrf().disable()
  16.                 //不通过Session获取SecurityContext
  17.                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  18.                 .and()
  19.                 .authorizeRequests()
  20.                 // 对于登录接口 允许匿名访问
  21.                 .antMatchers("/login").anonymous()
  22.                 //jwt过滤器测试用,如果测试没有问题吧这里删除了
  23.                 .antMatchers("/link/getAllLink").authenticated()
  24.                 // 除上面外的所有请求全部不需要认证即可访问
  25.                 .anyRequest().permitAll();
  26.         http.logout().disable();
  27.         //***2,把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中
  28.         http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
  29.         //允许跨域
  30.         http.cors();
  31.     }
  32.     @Bean
  33.     public PasswordEncoder passwordEncoder(){
  34.         return new BCryptPasswordEncoder();
  35.     }
  36. }
复制代码
*** Redis使用FastJson序列化

[code]package com.lwq.config;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;import com.fasterxml.jackson.databind.JavaType;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.type.TypeFactory;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.SerializationException;import com.alibaba.fastjson.parser.ParserConfig;import org.springframework.util.Assert;import java.nio.charset.Charset;/** * Redis使用FastJson序列化 *  * @author sg */public class FastJsonRedisSerializer implements RedisSerializer{    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");    private Class clazz;    static    {        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);    }    public FastJsonRedisSerializer(Class clazz)    {        super();        this.clazz = clazz;    }    @Override    public byte[] serialize(T t) throws SerializationException    {        if (t == null)        {            return new byte[0];        }        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);    }    @Override    public T deserialize(byte[] bytes) throws SerializationException    {        if (bytes == null || bytes.length
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

尚未崩坏

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表