SpringSecurity学习笔记(四)-通过自定义过滤器的方式,实现登录验证码功能(带源码下载)

5 篇文章 0 订阅
4 篇文章 0 订阅

1.一般实现登录验证码,有两种思路
(1)自定义过滤器
(2)自定义认证逻辑
2.本次通过自定义过滤器实现验证码,之前也写过一篇笔记,是基于自定义认证逻辑实现的,有兴趣的同学可参见:基于SpringBoot+SpringSecurity+VUE实现登录验证码功能-自定义认证逻辑方式(带源码下载)

源码下载链接请见文末。

如果想看SpringSecurity其他笔记,请见:SpringSecurity学习笔记

1.添加kaptcha依赖

<!--  添加kaptcha依赖 -->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

2.对kaptcha进行配置

/**
 * 对kaptcha进行配置
 */
@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");
        // 设置验证码为4位
        properties.setProperty("kaptcha.textproducer.char.length","4");

        Config config=new Config(properties);
        DefaultKaptcha defaultKaptcha=new DefaultKaptcha();
        defaultKaptcha.setConfig(config);

        return defaultKaptcha;

    }
}

3.写一个接口,让登录页面获取生成的验证码

@RestController
public class VertificationCodeController {

    @Autowired
    Producer producer;

    @GetMapping("/vc.jpg")
    public void getVerifyCode(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        response.setContentType("image/jpeg");
        String text=producer.createText();
        // 把生成的验证码保存到session中
        session.setAttribute("kaptcha",text);
        // 把生成的验证码生成图片
        BufferedImage image=producer.createImage(text);
        try (ServletOutputStream out=response.getOutputStream()){
            ImageIO.write(image,"jpg",out);

        }
    }
}

4.修改SecurityConfig.java,允许登录页面访问/vc.jpg获取验证码

 @Override
 protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/vc.jpg").permitAll()
        //此处省略其他
}

               
5.添加LoginFilter过滤器

public class LoginFilter extends UsernamePasswordAuthenticationFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        if(!request.getMethod().equals("POST")){
            throw new AuthenticationServiceException("非post类型"+request.getMethod());
        }

        String kaptcha=request.getParameter("kaptcha");
        String sessionKaptcha=(String)request.getSession().getAttribute("kaptcha");
        if(!StringUtils.isEmpty(kaptcha)&&!StringUtils.isEmpty(sessionKaptcha)&&kaptcha.equals(sessionKaptcha)){
            return super.attemptAuthentication(request,response);
        }
        throw new AuthenticationServiceException("验证码不正确");
    }
}


6.在SecurityConfig.java配置验证码校验
 

@Configuration
    @Order(1)
    static class SecurityConfig01 extends WebSecurityConfigurerAdapter{
        @Autowired
        MyUserDetailsService myUserDetailsService;

        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }

        // 配置验证码有效
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception{
            return super.authenticationManagerBean();
        }

        @Bean
        LoginFilter loginFilter() throws Exception{
            LoginFilter loginFilter=new LoginFilter();
            loginFilter.setFilterProcessesUrl("/doLogin");
            loginFilter.setAuthenticationManager(authenticationManagerBean());
            loginFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
            loginFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
            return loginFilter;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //添加过滤器
            http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
            // 此处省略其他
        }
        // 此处省略其他

    }

7.修改前端login登录页面

<template>
    <div class="login_container">
        <div class="login_bigbox">

            <span class="title_span">人事管理系统</span>
            <div class="login_box">
                <el-form ref="loginFormRef" :model="loginForm"  label-width="" class="login_form" :rules="loginFormRules">
                    <el-form-item label="" prop="username">
                        <el-input v-model="loginForm.username" prefix-icon="el-icon-user" ></el-input>
                    </el-form-item>
                    <el-form-item label="" prop="password">
                        <el-input v-model="loginForm.password" prefix-icon="el-icon-lock" type="password"></el-input>
                    </el-form-item>
                    <el-form-item label="" prop="kaptcha" width="50%">
                        <el-input v-model="loginForm.kaptcha" prefix-icon="el-icon-lock"></el-input>
                    </el-form-item>
                    <el-form-item label=""  width="50%"><img :src="validateUrl" alt="" @click="reflashImg"></el-form-item>
                    <el-form-item class="btns">
                        <el-button type="primary" @click="login">登录1</el-button>
                        <el-button type="info" @click="reset">重置</el-button>
                    </el-form-item>
                </el-form>
            </div>
        </div>

    </div>
</template>
<script>
import Qs from 'qs'
export default {
  data () {
    return {
      validateUrl: 'http://localhost:1025/vc.jpg',
      loginForm: {
        username: 'admin',
        password: '123',
        kaptcha: ''
      },
      loginFormRules: {
        username: [
          { required: true, message: '用户名不能为空', trigger: 'blur' },
          { min: 3, max: 20, message: '用户名必须在3-20个字符之间', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '密码不能为空', trigger: 'blur' },
          { min: 3, max: 20, message: '密码必须在3-20个字符之间', trigger: 'blur' }
        ],
        kaptcha: [
          { required: true, message: '验证码不能为空', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    login () {
      // sm2加密
      // const sm2 = require('sm-crypto').sm2
      // const cipherMode = 1
      // const pwd = sm2.doEncrypt(this.password, '公钥', cipherMode)
      // let sm2 = require('sm-crypto').sm2

      // console.log('pwd:' + sm2)

      // 先进行表单预验证
      this.$refs.loginFormRef.validate(async valid => {
        if (valid === true) {
        // 表单预验证通过,向后台发送请求
          // this.$http.post('login', Qs.stringify(this.loginForm))
          this.$http.post('doLogin', Qs.stringify(this.loginForm))
            .then(res => {
              console.log(res.data)
              if (res.data.status === 200) {
                const token = res.data.token
                // this.$message.success('登录成功')
                // 保存token
                sessionStorage.setItem('token', token)
                this.$router.push('/home')
              } else if (res.data.status === 401) {
                this.$message.error('登录失败,' + res.data.msg)
              } else {
                this.$message.error('其他未知错误')
              }
            })
            .catch(error => {
              const error2 = error + ''
              if (error2.indexOf('401') !== -1) { this.$message.error('用户名或密码错误') } else this.$message.error('外星人把我们的服务器劫走了,刷新一下也许能抢回来哦!')
            })
        }
      })
    },
    reset () {
      this.$refs.loginFormRef.resetFields()
      this.$message.success('已重置登录框')
    },
    reflashImg () {
      console.log('hahahdkhfalksdf')
      var timstamp2 = (new Date()).valueOf()
      this.validateUrl = 'http://localhost:1025/vc.jpg?t=' + timstamp2
    }
  }

}
</script>
<style lang="less" scoped>
.login_container{
    background-color: #2b4b6b;
    //background-color: #555;
    height: 100%;
}
.login_bigbox{
    width: 350px;
    height: 450px;
    //background-color: #eee;
    border-radius: 3px;
    position: absolute;
    text-align: center;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
}
.title_span{
    font-size: 35px;
    width: 350px;
    font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif;
    position: absolute;
    left: 50%;
    transform: translate(-50%,-150%);
}
.login_box{
    width: 350px;
    height: 400px;
    background-color: #fff;
    border-radius: 3px;
}
.btns{
    display:flex;
    justify-content: flex-end;
}
.login_form{
    position: absolute;
    bottom: 15%;
    width: 100%;
    padding: 10px 20px;
    box-sizing: border-box;
}
</style>

源下载地址:带验证码的登录功能-基于自定义过滤器-demo-Java文档类资源-CSDN文库

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaokang2216

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值