首页 > 其他分享 >SpringSecurity 添加验证码的两种方式

SpringSecurity 添加验证码的两种方式

时间:2023-05-30 14:14:54浏览次数:43  
标签:return 登录 验证码 SpringSecurity 添加 new http public

一 验证码生产

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>
@Configuration
public class KaptchaConfig {
    @Bean
    Producer kaptcha() {
        Properties properties = new Properties();
        properties.setProperty("kaptcha.image.width", "150");
        properties.setProperty("kaptcha.image.height", "50");
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
@RestController
public class LoginController {
    @Autowired
    Producer producer;
    @GetMapping("/vc.jpg")
    public void getVerifyCode(HttpServletResponse resp, HttpSession session) throws IOException {
        resp.setContentType("image/jpeg");
        String text = producer.createText();
        session.setAttribute("kaptcha", text);
        BufferedImage image = producer.createImage(text);
        try(ServletOutputStream out = resp.getOutputStream()) {
            ImageIO.write(image, "jpg", out);
        }
    }
}

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户登陆</title>
</head>
<body>
<h2>登录页面</h2>
<!--${param.error}这个如果有值,就显示帐号或密码错误-->
<h4 th:if="${session.errorMsgs}" style="color: #c41f1f;">帐号或密码错误,请重新输入</h4>
<form action="/login/doLogin" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="uname" value="zhangsan"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="pwd" value="123456"></td>
        </tr>
        <td>验证码:</td>
        <td><input type="text" name="code"> <img src="/vc.jpg" style="height:33px;cursor:pointer;"
                                                 onclick="this.src=this.src">
            <span th:text="${session.errorMsg}" style="color: #FF0000;"></span>
        </td>
        <tr>
            <td colspan="2">
                <button type="submit">登录</button>
                <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
            </td>
        </tr>
    </table>
</form>
</body>
        

 

 

二 添加过滤器认证

 UsernamePasswordAuthenticationFilter收集用户名和密码,之前添加一个校验验证码的过滤器,通过配置加入到过滤器链。

 

@Component
public class ValidateCodeFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //得到请求地址
        String requestURI = request.getRequestURI();
        System.out.println("requestURL" + requestURI);

        //判断是否是登录请求
        if (requestURI.equals("/login/doLogin")) {
            //说明当前请求为登陆
            //1,得到登陆时用户输入的验证码
            String code1 = request.getSession().getAttribute("kaptcha").toString();
            String code = request.getParameter("kaptcha");
            System.out.println("用户输入的验证码:" + code);
            if (StringUtils.hasText(code)) {
                if (code.equalsIgnoreCase(code1)) {
                    //说明验证码正确  直接放行
                    request.getSession().removeAttribute("errorMSg");
                    filterChain.doFilter(request, response);
                    return;
                } else {
                    //说明验证码不正确,返回登陆页面
                    request.getSession().setAttribute("errorMsg", "验证码错误");
                    response.sendRedirect("/index/toLogin");
                    return;
                }
            } else {
                //用户没有输出验证码重定向到登陆页面
                request.getSession().setAttribute("errorMsg", "验证码不能为空");
                response.sendRedirect("/index/toLogin");
                return;
            }
        } else {
            //说明不是登陆 直接放行到下一个过滤器
            filterChain.doFilter(request, response);
            return;
        }

    }
}

 

 

 

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /*注入 登录成功处理器*/
    @Autowired
    private AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;

    /*注入 登录 失败处理器*/
    @Autowired
    private AppAuthenticationFailureHandler appAuthenticationFailureHandler;

    /*注入  没有权限处理器*/
    @Autowired
    private AppAccessDeniedHandler appAccessDeniedHandler;

    /*注入 登出成功处理器*/
    @Autowired
    private AppLogoutSuccessHandler appLogoutSuccessHandler;

    @Autowired
    private AppUserDetailsService appUserDetailsService;

    //验证码拦截器注入
    @Autowired
    private ValidateCodeFilter validateCodeFilter;

    /*配置多用户*/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(appUserDetailsService);
    }

    /*http请求配置*/

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        super.configure(http);// 不使用父类的 方法, 需要 提供登录配置
        /*没权权限的处理*/
//        http.exceptionHandling().accessDeniedHandler(appAccessDeniedHandler);
        /*登录*/
        // 配置登录之前添加一个验证码的过滤器
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http.formLogin()
                .usernameParameter("uname")//页面表单账号的参数名  默认 为 username
                .passwordParameter("pwd")//页面表单密码的参数名   默认 为 password
                .loginPage("/index/toLogin")//定义登录页面的 请求 地址(转发到登录页面)
                .loginProcessingUrl("/login/doLogin")// 表单提交的 地址(不需要提供),登录验证.....
                .successForwardUrl("/index/toIndex")//登录成功 跳转的路径
                .failureForwardUrl("/index/toLogin")//登录失败 跳转的路径
//                .successHandler(appAuthenticationSuccessHandler)//登录成功处理器
//                .failureHandler(appAuthenticationFailureHandler)//登录失败处理器
                .permitAll();
        ;

        /*登出*/
        http.logout()
                .logoutUrl("/logout")//登出的 请求地址
                .logoutSuccessUrl("/index/toLogin")//登出成功后 访问的路径
//                .logoutSuccessHandler(appLogoutSuccessHandler)//登出成功处理器
                .permitAll()
        ;
          /*设置 资源所需要的 权限 (好比 门上锁)*/
        http.authorizeRequests()
//                .mvcMatchers("/index/toLogin", "/index.html","/code/img").permitAll()//不需要认证就可以访问
                .antMatchers("/code/img")  // 放行验证码的路径
                .permitAll()
                .anyRequest().authenticated()//所有请求都需要登录认证 才能进行

        ;
        /*禁用csrf跨域请求攻击   如果不禁用  自定义的登录页面无法登录*/
        http.csrf().disable();
    }

    /*资源服务匹配放行:静态资源*/
    @Override
    public void configure(WebSecurity web) throws Exception {
//        super.configure(web);
        web.ignoring().antMatchers("/css/**");
    }

    /*强制要求配置 密码加密器*/
    @Bean// 将对象 交给 spring容器 管理
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();//不加密
        return new BCryptPasswordEncoder();
    }

}

 

 

 

 

 

 

三 自定义认证

 

UsernamePasswordAuthenticationFilter收集用户名和密码后,要往ProviderManager--DaoAuthenticationProvider--InMemoryUserDetailsManager/UserDetailsService传递。

我们可以继承原有DaoAuthenticationProvider类重写其方法,让在调用UserDetailsService之前,校验验证码。

 

 身份认证是 AuthenticationProvider 的 authenticate 方法完成,因此验证码可以在此之前完成:

public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String kaptcha = req.getParameter("kaptcha");
        String sessionKaptcha = (String) req.getSession().getAttribute("kaptcha");
        if (kaptcha != null && sessionKaptcha != null && kaptcha.equalsIgnoreCase(sessionKaptcha)) {
            return super.authenticate(authentication);
        }
        throw new AuthenticationServiceException("验证码输入错误");
    }
}

配置 AuthenticationManager:(旧方式继承WebSecurityConfigurerAdapter )

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    AuthenticationProvider kaptchaAuthenticationProvider() {
        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(User.builder()
                .username("xiepanapn").password("{noop}123").roles("admin").build());
        KaptchaAuthenticationProvider provider = new KaptchaAuthenticationProvider();
        provider.setUserDetailsService(users);
        return provider;
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        ProviderManager manager = new ProviderManager(kaptchaAuthenticationProvider());
        return manager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/vc.jpg").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/mylogin.html")
                .loginProcessingUrl("/doLogin")
                .defaultSuccessUrl("/index.html")
                .failureForwardUrl("/mylogin.html")
                .usernameParameter("uname")
                .passwordParameter("passwd")
                .permitAll()
                .and()
                .csrf().disable();
    }
}

新方式过滤器链

@Configuration
@EnableWebSecurity    // 添加 security 过滤器
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)    // 启用方法级别的权限认证
public class SecurityWebConfig {

    @Autowired(required=true)
    public UserDetailsService userDetailsServiceImpl;

    @Bean
    AuthenticationProvider kaptchaAuthenticationProvider() {
        //内存认证
        //InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(User.builder().username("xiepanapn").password("{noop}123").roles("admin").build());
        //provider.setUserDetailsService(users);

        //userDetailsService认证
        KaptchaAuthenticationProvider provider = new KaptchaAuthenticationProvider();
        provider.setUserDetailsService(userDetailsServiceImpl);
        return provider;
    }

    /**
     * 获取AuthenticationManager(认证管理器),登录时认证使用
     * @param authenticationConfiguration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        //return authenticationConfiguration.getAuthenticationManager(); //方式一
        ProviderManager manager = new ProviderManager(kaptchaAuthenticationProvider());  //方式二,(验证码)
        return manager;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 注解标记允许匿名访问的url
        //ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        //permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());

        http
            // 基于 web,需要 csrf (其实不用配置,默认支持)
            .csrf().and()
            // 基于 web,需要 session  (其实不用配置,默认支持)
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS).and()
            // 下面开始设置权限过滤请求
            .authorizeRequests(authorize -> authorize
                    // 请求放开
                    .antMatchers("/index","/index1","/index2","/index3").permitAll()
                    // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                    .antMatchers("/login", "/register", "/captchaImage").permitAll()
                    // 静态资源,可匿名访问
                    .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                    .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                    // 其他地址的访问均需验证权限
                    .anyRequest().authenticated()
            );
            // 认证用户时用户信息加载配置,注入springAuthUserService  (其实不用配置,默认实现接口即可调用)
            //.userDetailsService(userDetailsServiceImpl);

        //请求过滤规则

        //指定登录表单的规则
        http.formLogin()
            //这个路径必须和登录表单的提交路径一致。
            .loginProcessingUrl("/login")
            //设置自定义登录界面
            .loginPage("/login.html")
            //登录成功后转发的路径
            .successForwardUrl("/main")
            //登录失败跳转地址
            .failureForwardUrl("/fail")
            .permitAll();

        //登出配置
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/").clearAuthentication(true);

        //记住我功能

        //没有权限时跳转的路径
        http.exceptionHandling().accessDeniedPage("/403.html");
        return http.build();
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
    /**
     * 配置跨源访问(CORS)
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
    
}

 

 

 

  1. 配置 UserDetailsService 提供的数据源

  2. 提供 AuthenticationProvider 实例,并配置 UserDetailsService

  3. 重写 authenticationManagerBean 方法提供一个自己的 ProviderManager 并自定义 AuthenticationManager 实例。

 

 

 

 

 

转: https://xie.infoq.cn/article/a5614c477aa97be61ae2a0ee6

https://blog.csdn.net/qq_51307593/article/details/127561058

https://www.cnblogs.com/dalianpai/p/14744704.html

 

标签:return,登录,验证码,SpringSecurity,添加,new,http,public
From: https://www.cnblogs.com/fps2tao/p/17442725.html

相关文章

  • k8s源码中给操作添加追踪功能
    不是很能看懂,但是又觉得很有用,不定什么时候能用到,先记录到这里吧operation.go/*Copyright2014GoogleInc.Allrightsreserved.LicensedundertheApacheLicense,Version2.0(the"License");youmaynotusethisfileexceptincompliancewiththeLicense.Youmay......
  • SpringSecurity集成启动报 In the composition of all global method configuration,
    一.异常内容Causedby:org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname'methodSecurityMetadataSource'definedinclasspathresource[org/springframework/security/config/annotation/method/configuration/GlobalMet......
  • 图片验证码
    图片验证码Captchaisoneofthemodernwaysusedforverificationinwebsites;itisverycoolwayandeverysecondwebsiteisusingit.YoucanuseGooglecaptchabutitisreallyaheadachetoapplyit;howeverinDjango,wehaveasimplermethodtodoso.......
  • web基础漏洞-验证码爆破
    1、介绍这里的验证码是指在注册、登录、找回密码、重要操作验证身份时,服务端向用户的手机或者邮箱发送验证码,用户输入匹配成功以验证身份。验证码爆破漏洞,是服务端未进行次数和时间限制,或者允许的范围过大。导致攻击者可以反复尝试不同的验证码,以获取到正确的验证码。2、测试......
  • VSTO添加右键菜单
    以Word为例privatevoidAddRightMenu(){Microsoft.Office.Core.CommandBarmzBar=appWord.CommandBars["Text"];//word文档已有的右键菜单TextMicrosoft.Office.Core.CommandBarmzBar=appExcel.CommandBars["cell"];......
  • Android Studio 添加汉化包
    1.查看自己androidstudio软件版本   我的版本为222那么需下载222的汉化包2.点击这里前往下载相应版本的汉化包小版本无需注意,大版本对就可以。我这里选择为 下载后再进行解压3.导入汉化包 选择好下载文件的路径并导入,然后会提示需要重新启动,重启后即可 ......
  • 验证码模型训练与识别
    1.训练模型代码importnumpyasnpimporttensorflowastf#importtensorflow.compat.v1astf#tf.disable_v2_behavior()fromcaptcha.imageimportImageCaptchaimportnumpyasnpimportmatplotlib.pyplotaspltfromPILimportImageimportrandomnumber=......
  • IDEA 在pom.xml中添加maven 依赖包时下载依赖包速度很慢-解决
     IDEA在pom.xml中添加maven依赖包时下载依赖包速度很慢-解决 右键项目选中maven选项,然后选择“opensettings.xml”或者“createsettings.xml”。如果之前没有创建过,就是“createsettings.xml”,我已经修改过了,所以只出现“opensettings.xml”  <?xmlversion="......
  • PM添加Cookie
    ......
  • FreeSWITCH添加自定义endpoint
    操作系统:CentOS7.6_x64   FreeSWITCH版本:1.10.9 日常开发过程中会遇到需要扩展FreeSWITCH对接其它系统的情况,这里记录下编写FreeSWITCH自定义endpoint的过程。一、模块定义函数使用FreeSWITCH自带的框架来定义模块函数,函数指针及参数列表定义如下(src/include/switc......