SpringSecurity认证笔记

Spring Security 是 Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。本文为学习三更草堂B站视频做个笔记便于回顾。

引入依赖

       
            org.springframework.boot
            spring-boot-starter-security
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            com.alibaba
            fastjson
            1.2.78
        
        
            com.auth0
            java-jwt
            4.0.0
        

SpringSecurity完整流程

SpringSecurity认证笔记_第1张图片

UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。

ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException。

FilterSecurityInterceptor:负责权限校验的过滤器。

认证流程详解

SpringSecurity认证笔记_第2张图片

Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。

AuthenticationManager接口:定义了认证Authentication的方法

UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。

UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。

自定义登录接口

调用ProviderManager的方法进行认证 如果认证通过生成jwt。把用户信息存入redis中,自定义UserDetailsService。在这个实现类中去查询数据库。

校验:

定义Jwt认证过滤器

​ 获取token解析token获取其中的userid,从redis中获取用户信息存入SecurityContextHolder。

JWT,Redis工具类在之前的文章存有,这里省略。

SpringSecurity配置类

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    Au au;

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/alipay/pay").permitAll()
                .antMatchers("/alipay/notify").permitAll()
                .antMatchers("/user/login").permitAll()
                .antMatchers("/register").permitAll().anyRequest().authenticated();
        http.cors();//允许跨域
        http.exceptionHandling().authenticationEntryPoint(au);//配置认证失败处理器

            http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);


    }



}

登录接口

 @PostMapping("/user/login")
    public Map login1(@RequestBody User user){
        Map map=new HashMap<>();
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(user.getLoginname(),user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if(authenticate==null){
            map.put("list","error");
        }
        else {
            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
            Long id = loginUser.getUser().getId();
         String token = JwtUtil.generateToken(id);
//            redisUtil.set(String.valueOf(id), loginUser.getUser());
            map.put("list","success");
            map.put("token",token);
        }
       return map;
    }

LoginUser实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails, Serializable {
    private User user;
    @Override
    public Collection getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getLoginname();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

UserDetailsService接口

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String loginname) throws UsernameNotFoundException {
        User user = userMapper.selectOneByLoginname(loginname);
        if(user==null){
            throw new RuntimeException("用户名或者密码错误");
        }
        return new LoginUser(user);
    }
}

设置拦截器,这里的代码做了变动,因为在原先的代码,登录之后token过期不退出登录然后重新登陆就会报异常错误。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    RedisUtil redisUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader("token");
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        Long userId;
        try {
            DecodedJWT decodedJWT = JwtUtil.decodeToken(token);
            userId = decodedJWT.getClaim("userId").asLong();
        }catch (Exception e){
            e.printStackTrace();
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
//      User user =(User) redisUtil.get(String.valueOf(userId));
//        if(Objects.isNull(user)){
//            filterChain.doFilter(httpServletRequest,httpServletResponse);
//            return;
//        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(null,null,null);
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

设置认证失败处理器

@Component
public class Au implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setStatus(200);
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().print("用户认证失败");
    }
}

你可能感兴趣的:(Springboot,spring,spring,boot,java)