美文网首页
2023-12-26 生成/校验图片验证码

2023-12-26 生成/校验图片验证码

作者: 大也 | 来源:发表于2024-01-01 10:28 被阅读0次

    注意点 hutool jar包 内功能的认识

    image.png
    image.png

    人话


    6bb071e350bc3af0dce8c435ded813f2.jpg

    -----生成
    1.model
    @Data
    @Schema(description = "验证码响应结果实体类")
    public class ValidateCodeVo {

    /**
     // 验证码的key
     * */
    @Schema(description = "验证码key")
    private String codeKey ;
    
    /**
     // 图片验证码对应的字符串数据
     * */
    @Schema(description = "验证码value")
    private String codeValue ;
    

    }

    2.controller
    /**
    图片验证码
    * */
    @Autowired
    private ValidateCodeService validateCodeService;

    /**
     1.通过工具生成图片二维码 // hutool
     2。把验证码存储到redis key uuid value验证码值
     设置过期时间
     3。返回对象 ValidateCodeVo
     * */
    @GetMapping("generateValidateCode")
    public  Result<ValidateCodeVo> generateValidateCode(){
        ValidateCodeVo validateCodeVo = validateCodeService.generateValidateCode();
        return Result.build(validateCodeVo , ResultCodeEnum.SUCCESS) ;
    }
    

    3.Service
    /**

    • className:{ValidateCodeService}
      /
      public interface ValidateCodeService {
      /
      *
      生成验证码
      • */
        ValidateCodeVo generateValidateCode() ;
        }
        3.1ServiceImpl

    /**

    • className:{ValidateCodeServiceImpl}
      */
      @Service
      public class ValidateCodeServiceImpl implements ValidateCodeService {

      @Autowired
      private RedisTemplate<String,String> redisTemplate;

      /**
      生成验证码

      • /
        @Override
        public ValidateCodeVo generateValidateCode() {
        /
        *
        1.通过工具生成图片二维码 // hutool
        2。把验证码存储到redis key uuid value验证码值
        设置过期时间
        3。返回对象 ValidateCodeVo
        • */
          //1
          CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(150,48,4,2);
          String code = circleCaptcha.getCode();
          String imageStr = circleCaptcha.getImageBase64();
          //2
          String key = UUID.randomUUID().toString().replaceAll("-","");
          redisTemplate.opsForValue().set("user:validate"+key,code,5, TimeUnit.MINUTES);
          ValidateCodeVo validateCodeVo = new ValidateCodeVo();
          validateCodeVo.setCodeKey(key);
          validateCodeVo.setCodeValue("data:image/png;base64,"+imageStr);
          return validateCodeVo;
          }
          }
          -----校验。在登陆逻辑里面校验

    /**10。1
    1.获取输入验证码和存储到redis的key名称 loginDto获取到
    2。根据获取的redis里面key ,查询redis里面存储验证码
    3 比较输入的验证码和 redis存储验证码是否一致
    4 如果不一致,提示用户,校验失败
    5 如果一致,删除redis里面验证码
    * */
    @Override
    public LoginVo adminSystemIndexLogin(LoginDto loginDto) {
    //10。1
    String captcha = loginDto.getCaptcha();
    String key = loginDto.getCodeKey();
    //10。2
    String redisTemplateCaptcha = redisTemplate.opsForValue().get("user:validate"+key);
    //10.3
    if (StrUtil.isEmpty(redisTemplateCaptcha) || !StrUtil.equalsIgnoreCase(captcha,redisTemplateCaptcha)) {
    //10.4
    throw new GuiguException(ResultCodeEnum.VALIDATECODE_ERROR);
    }
    //10.5
    redisTemplate.delete("user:validate"+key);

    //////////////////////////////////////////////
    生成/校验图片 前端代码修改

    'rules-validate-code': '验证码不能为空'


    image.png

    // 获取验证码
    export const GetValidateCode = () => {
    return request({
    url: "/admin/system/index/generateValidateCode",
    method: 'get'
    })
    }

    image.png
    3.替换

    <template>
    <div class="login">
    <el-form class="form" :model="model" :rules="rules" ref="loginForm">
    <h1 class="title">尚品甄选后台管理系统</h1>
    <el-form-item prop="userName">
    <el-input
    class="text"
    v-model="model.userName"
    prefix-icon="User"
    clearable
    :placeholder="t('login.username')" /> </el-form-item> <el-form-item prop="password"> <el-input class="text" v-model="model.password" prefix-icon="Lock" show-password clearable :placeholder="t('login.password')"
    />
    </el-form-item>
      <el-form-item prop="captcha">
          <div class="captcha">
              <el-input
                        class="text"
                        v-model="model.captcha"
                        prefix-icon="Picture"
                        placeholder="请输入验证码"
                        ></el-input>
              <img :src="captchaSrc" @click="refreshCaptcha" />
          </div>
      </el-form-item>
    
      <el-form-item>
        <el-button
          :loading="loading"
          type="primary"
          class="btn"
          size="large"
          @click="submit"
        >
          {{ btnText }}
        </el-button>
      </el-form-item>
    </el-form>
    

    </div>
    <div class="change-lang">
    <change-lang />
    </div>
    </template>

    <script>
    import {
    defineComponent,
    getCurrentInstance,
    reactive,
    toRefs,
    ref,
    computed,
    onMounted,
    watch,
    } from 'vue'
    import { Login , GetValidateCode } from '@/api/login'
    import { useRouter, useRoute } from 'vue-router'
    import ChangeLang from '@/layout/components/Topbar/ChangeLang.vue'
    import useLang from '@/i18n/useLang'
    import { useApp } from '@/pinia/modules/app'

    export default defineComponent({
    components: { ChangeLang },
    name: 'login',
    setup() {
    const { proxy: ctx } = getCurrentInstance() // 可以把ctx当成vue2中的this
    const router = useRouter()
    const route = useRoute()
    const { lang } = useLang()
    watch(lang, () => {
    state.rules = getRules()
    })
    const getRules = () => ({
    userName: [
    {
    required: true,
    message: ctx.t('login.rules-username'), trigger: 'blur', }, ], password: [ { required: true, message: ctx.t('login.rules-password'),
    trigger: 'blur',
    },
    {
    min: 6,
    max: 12,
    message: ctx.t('login.rules-regpassword'), trigger: 'blur', }, ], captcha: [ { required: true, message: ctx.t('login.rules-validate-code'),
    trigger: 'blur',
    },
    ],

    })
    
    // onMounted钩子函数
    onMounted(() => {
      state.refreshCaptcha()
    })
    
    const state = reactive({
      model: {
        userName: 'admin',
        password: '111111',
        captcha: '',      // 用户输入的验证码
        codeKey: ''       // 后端返回的验证码key
      },
      rules: getRules(),
      loading: false,
      captchaSrc: "" ,
      refreshCaptcha: async () => {
          const { data } = await GetValidateCode() ;
          state.model.codeKey = data.codeKey
          state.captchaSrc = data.codeValue
      },
      btnText: computed(() =>
        state.loading ? ctx.$t('login.logining') : ctx.$t('login.login')
      ),
      loginForm: ref(null),
      submit: () => {
        if (state.loading) {
          return
        }
        state.loginForm.validate(async valid => {
          if (valid) {
            state.loading = true
            const { code, data, message } = await Login(state.model)
            if (+code === 200) {
              ctx.$message.success({
                message: ctx.$t('login.loginsuccess'),
                duration: 1000,
              })
    
              const targetPath = decodeURIComponent(route.query.redirect)
              if (targetPath.startsWith('http')) {
                // 如果是一个url地址
                window.location.href = targetPath
              } else if (targetPath.startsWith('/')) {
                // 如果是内部路由地址
                router.push(targetPath)
              } else {
                router.push('/')    // 请求成功以后,进入到首页
              }
              useApp().initToken(data)
            } else {
              ctx.$message.error(message)
            }
            state.loading = false
          }
        })
      },
    })
    
    return {
      ...toRefs(state),
    }
    

    },
    })
    </script>

    <style lang="scss" scoped>
    .login {
    transition: transform 1s;
    transform: scale(1);
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #2d3a4b;
    .form {
    width: 520px;
    max-width: 100%;
    padding: 0 24px;
    box-sizing: border-box;
    margin: 160px auto 0;
    :deep {
    .el-input__wrapper {
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1) inset;
    background: rgba(0, 0, 0, 0.1);
    }
    .el-input-group--append > .el-input__wrapper {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    }
    .el-input-group--prepend > .el-input__wrapper {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    }
    }
    .title {
    color: #fff;
    text-align: center;
    font-size: 24px;
    margin: 0 0 24px;
    }
    .text {
    font-size: 16px;
    :deep(.el-input__inner) {
    color: #fff;
    height: 48px;
    line-height: 48px;
    &::placeholder {
    color: rgba(255, 255, 255, 0.2);
    }
    }
    }
    .btn {
    width: 100%;
    }
    }
    }

    .captcha {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
    }

    .captcha img {
    cursor: pointer;
    margin-left: 20px;
    }

    .change-lang {
    position: fixed;
    right: 20px;
    top: 20px;
    :deep {
    .change-lang {
    height: 24px;
    &:hover {
    background: none;
    }
    .icon {
    color: #fff;
    }
    }
    }
    }
    </style>

    image.png

    相关文章

      网友评论

          本文标题:2023-12-26 生成/校验图片验证码

          本文链接:https://www.haomeiwen.com/subject/dhykndtx.html