用户登录
用户注册

分享至

SpringScurity实现图片验证码功能

  • 作者: 内涵的射手
  • 来源: 51数据库
  • 2021-10-19

?

?

前言

整个小案例采用的是ssm+jsp+springscurity的技术

1.导入依赖坐标

? ? ? ? ? ? ? ?

2.编写验证码功能

我的验证码部分代码是写在后台的,并且封装成了一个工具类

package utils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class CheckCodeUtils {
    public static final String CHECKCODE_KEY = "checkCode_key";
    private static Random random=new Random();

    private static String randStr="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static int width=80 ;
    private static int height=26 ;
    private static int lineNum=10 ;
    private static int strNum=4 ;

    private String randString;


    //获取随机验证码
    public   void getCheckCode(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
        Graphics graphics = image.getGraphics();
        graphics.fillRect(0,0,width,height);
        graphics.setFont(new Font("Times New Roman",Font.ROMAN_BASELINE,18));
        graphics.setColor(getRandColor(160, 200));
        //绘制干扰线
        for(int i=0;i<=lineNum;i++){
            drowLine(graphics);
        }
        //绘制随机字符
         randString = "";
        for(int i=1;i<=strNum;i++){
            randString=drowString(graphics,randString,i);
        }
        session.removeAttribute(CHECKCODE_KEY);
        session.setAttribute(CHECKCODE_KEY, randString);
        graphics.dispose();
        try {
            //将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /*
     * 获得字体
     */
    private  Font getFont(){
        return new Font("Fixedsys",Font.CENTER_BASELINE,18);
    }
    /*
     * 获得颜色
     */
    private  Color getRandColor(int fc, int bc){
        if(fc > 255)
            fc = 255;
        if(bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc-fc-16);
        int g = fc + random.nextInt(bc-fc-14);
        int b = fc + random.nextInt(bc-fc-18);
        return new Color(r,g,b);
    }

    /*
     * 绘制字符串.
     */
    private  String drowString(Graphics g, String randomString, int i){
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101),random.nextInt(111),random.nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(randStr.length())));
        randomString +=rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13*i, 16);
        return randomString;

    }
    /*
     * 绘制干扰线
     */
    private  void drowLine(Graphics g){
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.drawLine(x, y, x+xl, y+yl);
    }
    /*
     * 获取随机的字符
     */
    public  String getRandomString(int num){
        return String.valueOf(randStr.charAt(num));
    }
/*比较*/
    public String getRandString() {
        return randString;
    }

    public void setRandString(String randomString) {
        this.randString = randomString;
    }
}

类似的图片验证码的工具类网络上也是一大堆,可以自行查找

3.前端页面

<!--验证码栏-->
        <div class="usernameWrapDiv">
            <div class="layui-form-item layui-inline" >
                <label class="layui-form-label"><i class="layui-icon layui-icon-vercode"></i>验证: </label>
                    <div class="cardDiv">
                        <input id="loginCard" class="layui-input cardInput" type="text" name="loginCard" placeholder="输入验证码">
                    </div>
                    <div class="codeDiv">
                        <img name="imageCode" src="${pageContext.request.contextPath}/user/checkCode.do" alt="" width="100" height="32" class="layui-input codeInput" style="height:37.99px;cursor:pointer;"onclick="this.src=this.src+'?'">
                    </div>
            </div>
        </div>

4.Controller

@Controller
@RequestMapping("/user")
public class UserController {

    CheckCodeUtils utils;

    @RequestMapping("/checkCode.do")
    public void checkCode(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //设置相应类型,告诉浏览器输出的内容为图片
        utils = new CheckCodeUtils() ;
        response.setContentType("image/jpeg");

        //设置响应头信息,告诉浏览器不要缓存此内容
        response.setHeader("pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        try {
            utils.getCheckCode(request, response);//输出图片方法
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

5.实现自定义的图片验证码filter

?

public class ImageCodeAuthenticationFilter extends OncePerRequestFilter {

    private AuthenticationFailureHandler authenticationFailureHandler;

    public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
        this.authenticationFailureHandler = authenticationFailureHandler;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().contains("/securityLogin")) {
            try {
                String inputImageCode = request.getParameter("loginCard");
                String outputImageCode = (String) request.getSession().getAttribute("checkCode_key");
                
                if (StringUtils.isEmpty(inputImageCode.trim())) {
                    throw new ImageCodeException("验证码必须输入");
                }
                if (!inputImageCode.trim().equalsIgnoreCase(outputImageCode.trim())) {
                    throw new ImageCodeException("验证码错误");
                }
            }catch (AuthenticationException e){
                authenticationFailureHandler.onAuthenticationFailure(request,response,e);
                return;
            }
        }
        filterChain.doFilter(request,response);
    }
}

图片验证码异常类?


public class ImageCodeException  extends AuthenticationException {
    public ImageCodeException(String msg, Throwable t) {
        super(msg, t);

    }

    public ImageCodeException(String msg) {
        super(msg);

    }
}

自定义权限认证失败处理类


public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private ObjectMapper objectMapper = new ObjectMapper();



    @Override

    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        Map map = new HashMap();

        map.put("success", false);

        map.put("errorMsg", e.getMessage());

        String str = objectMapper.writeValueAsString(map);

        response.setContentType("text/json;charset=utf-8");
        request.getRequestDispatcher("/failer.jsp").forward(request,response);

    }

}

?如果认证失败直接是转发到failer.jsp界面

   request.getRequestDispatcher("/failer.jsp").forward(request,response);

6.SpringSecurity框架配置文件的修改

 // 定义类型为imageCodeAuthenticationFilter的Filter 并且在 FORM_LOGIN_FILTER (通俗点理解成表单登录Filter)前先过滤
<security:custom-filter ref="imageCodeAuthenticationFilter" before="FORM_LOGIN_FILTER"/>


//将ImageCodeAuthenticationFilter和MyAuthenticationFailureHandler 交给Spring容器来进行管理

<bean id="imageCodeAuthenticationFilter" class="security.ImageCodeAuthenticationFilter">

        <property name="authenticationFailureHandler" ref="myAuthenticationFailureHandler"/>

    </bean>
    <bean id="myAuthenticationFailureHandler" class="security.MyAuthenticationFailureHandler"/>

具体可以参考:https://blog.csdn.net/love1793912554/article/details/104298677

我觉得这里面一系列关于SpringSecurity的文章都写的很清晰也比较实用

?

?

软件
前端设计
程序设计
Java相关