springsecurity6使用

spring security 中的类 :

  • AuthenticationManager : 实现类:ProviderManager
    管理很多的 provider ,,, 经常使用的,DaoAuthenticationProvider , 这个要设置一个 UserDetailService , 查找数据库,,loadUserByUsername() 查找出数据库中的对象,,然后进行比对
spring security 中的配置

配置spring security 也就是配置 过滤器链,,spring security 他有默认的过滤器链,,,通过HttpSecurity 中的 build()方法,会返回一个默认的有拦截的过滤器链

我们一般都是在这个原本的过滤器链上面修改,,而不是重新创建自己的过滤器链,,

java 复制代码
    /**
     * 过滤器
     *  : 配置过滤器链
     *  DispatchServlet
     *
     *  DefaultLoginPageGeneratingFilter : 默认登录页面过滤器
     *  DefaultLogoutPageGeneratingFilter : 默认注销页面过滤器
     *  BasicAuthenticationFilter : 请求头认证过滤器
     */


    /**
     * 配置过滤器链  SecurityFilterChain,,spring security 所有功能都是通过过滤器链来提供
     */
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 拦截所有,,经过某些过滤器
//        return new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"));


        // 默认的过滤器链
//        return http.build();


         http.authorizeHttpRequests(p->p.anyRequest().authenticated())
                .formLogin(f->f.usernameParameter("username")
                        .passwordParameter("password")
                        .loginProcessingUrl("/login")
                        .successHandler((req,resp,auth)->{
                            resp.setContentType("application/json;charset=utf-8");
                            Hr hr = (Hr) auth.getPrincipal();
                            hr.setPassword(null);
                            resp.getWriter().write(new ObjectMapper().writeValueAsString(RespBean.ok("登录成功",hr)));
                        })
                        .failureHandler((req,resp,e)->{
                            resp.setContentType("application/json;charset=utf-8");
                            RespBean error = RespBean.error("登录失败");

                            if (e instanceof BadCredentialsException){
                                error.setMessage("密码错误");
                            }else if (e instanceof DisabledException){
                                error.setMessage("用户被禁用");
                            }else if (e instanceof LockedException){
                                error.setMessage("账户被锁定");
                            }else if (e instanceof AccountExpiredException){
                                error.setMessage("账户过期");
                            }else if(e instanceof CredentialsExpiredException){
                                error.setMessage("密码过期");
                            }

                            resp.getWriter().write(new ObjectMapper().writeValueAsString(error));
                        }))
                .csrf(c->c.disable())
                 //异常处理
                 .exceptionHandling(e->e.authenticationEntryPoint((req,resp,ex)->{
                     resp.setContentType("application/json;charset=utf-8");
                     resp.setStatus(401);
                     RespBean error = RespBean.error("尚未登陆,请登录");
                     resp.getWriter().write(new ObjectMapper().writeValueAsString(error));
                 }));

         // 加到 UsernamePasswordAuthenticationFilter前面
         http.addFilterBefore(jsonFilter(), UsernamePasswordAuthenticationFilter.class);

         return  http.build();

        /**
         * spring security 默认key-value
         * UsernamePasswordAuthenticationFilter
         */

    }

UsernamePasswordAuthenticationFilter : 这个是拦截提交的用户名密码的拦截器,,,里面有个attemptAuthentication() 去获取前端传入的用户名密码,

根据request获取的参数,,,

然而,我们需要通过json传参,,就需要重写这个方法,,并将自己的过滤器加入到spring security的过滤器链中,,

java 复制代码
/**
 * 登录传递json
 */
public class JsonFilter extends UsernamePasswordAuthenticationFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String contentType = request.getContentType();
        if (contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) || contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)){
            // 前端传入的是json
            try {
                // 通过io流,去解析请求体参数,,,比如:文件,json,,,   key-value也可以通过io流获取
                Hr hr = new ObjectMapper().readValue(request.getInputStream(), Hr.class);

                String username = hr.getUsername();
                String password = hr.getPassword();
                UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
                        password);
                // Allow subclasses to set the "details" property
                setDetails(request, authRequest);
                // 获取认证管理器去认证
                return this.getAuthenticationManager().authenticate(authRequest);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }else{
            //  key-value
            return super.attemptAuthentication(request,response);
        }




    }
}

自己新加的过滤器,需要配置自己的 AuthenticationManager , 和用户信息存放的位置:

java 复制代码
   /**
     * AuthenticationManager :
     *      实现类:   ProviderManager
     *      管理很多 provider
     * @return
     */
    @Bean
    AuthenticationManager authenticationManager(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();

        daoAuthenticationProvider.setUserDetailsService(hrService);

        ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider);
        return providerManager;
    }

配置了自己的 登录filter,, HttpSecurity中配置的formLogin 就失效了,,,需要自己配置loginProcessingUrl, successHandler,failureHandler等信息,,

需要配置自己的 AuthenticationManager 和表明登录信息的存放位子,,,,因为每一次都会从这个存放位置去找用户信息,,如果找到,表示已登录,如果没找到,就是没有登录

java 复制代码
   /**
     * 配置了  JsonFilter ,,,    httpsecurity 中的 fromLogin就失效了
     * @return
     */
    JsonFilter jsonFilter(){
        JsonFilter jsonFilter = new JsonFilter();
        jsonFilter.setFilterProcessesUrl("/login");
        jsonFilter.setAuthenticationSuccessHandler((req,resp,auth)->{
            resp.setContentType("application/json;charset=utf-8");
            Hr hr = (Hr) auth.getPrincipal();
            hr.setPassword(null);
            resp.getWriter().write(new ObjectMapper().writeValueAsString(RespBean.ok("登录成功",hr)));
        });
        jsonFilter.setAuthenticationFailureHandler((req,resp,e)->{
            resp.setContentType("application/json;charset=utf-8");
            RespBean error = RespBean.error("登录失败");

            if (e instanceof BadCredentialsException){
                error.setMessage("密码错误");
            }else if (e instanceof DisabledException){
                error.setMessage("用户被禁用");
            }else if (e instanceof LockedException){
                error.setMessage("账户被锁定");
            }else if (e instanceof AccountExpiredException){
                error.setMessage("账户过期");
            }else if(e instanceof CredentialsExpiredException){
                error.setMessage("密码过期");
            }

            resp.getWriter().write(new ObjectMapper().writeValueAsString(error));
        });


        // 需要设置自己的 AuthenticationManager
        jsonFilter.setAuthenticationManager(authenticationManager());

        /**
         *  每一次都会从 httpSession中获取用户,,如果httpsession中没有用户,就会表示成没有登录,,
         *  新配置的 filter 需要告知 ,,用户信息存放在哪里,,
         */

        // 自己配置的filter 需要设置 SecurityContextHolder 存储用户的位置
        jsonFilter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());

        return jsonFilter;
    }

这个用户信息可以存在HttpSessionSecurityContextRepositorysession中,,也可以重写类,存放在其他地方,比如redis

spring security 异常处理,,exceptionHandling, 中authenticationEntryPoint,处理登录失败异常

相关推荐
西凉的悲伤11 天前
Spring Security + JWT 登录认证完整实践指南
java·后端·spring·spring security·jwt
Micro麦可乐12 天前
最新Spring Security实战教程(十)权限表达式进阶 - 在SpEL在安全控制中的高阶魔法
java·spring boot·后端·spring·spring security·spel表达式
消失的旧时光-194317 天前
企业认证与安全体系(五):Spring Security + JWT + Redis 企业级认证实战
redis·安全·spring·spring security·jwt
消失的旧时光-194317 天前
企业认证与安全体系(四):企业登录认证流程全解析——JWT、Redis、Spring Security 如何协同工作?
redis·安全·spring·spring security·jwt
智研数智工坊18 天前
SpringBoot4.0.6 + Security7.x + JWT 最新完整实战|无状态权限认证、统一异常处理、可直接落地
java·spring boot·spring security·jwt·权限认证
段ヤシ.19 天前
回顾Java知识点,面试题汇总Day17(持续更新)
java·springboot·spring security·shiro·mybatis-plus·jdbctemplate·spring data jpa
梵得儿SHI23 天前
SpringCloud 进阶拓展:Spring Security OAuth2+JWT 微服务统一认证授权全实战|生产级方案 + 源码解析 + 踩坑实录
spring·spring cloud·微服务·spring security·jwt·oauth2·统一认证授权
Devin~Y1 个月前
互联网大厂 Java 面试实录:JVM、Spring Boot、MyBatis、Redis、Kafka、Spring AI、K8s 全链路追问小Y
java·jvm·spring boot·redis·kafka·mybatis·spring security
小坏讲微服务1 个月前
SpringBoot4.0整合Spring Security+MyBatis Plus完整权限框架实现
java·spring·mybatis·spring security·mybatis plus·springboot4.0
Cry丶2 个月前
架构师实战:Spring Authorization Server 落地企业级“无感” SSO(附设计映射与源码级接口剖析)
spring·spring security·oauth2.0·authorization·sso·无感登录