Spring security的圖片驗證碼方案一

在項目中使用spring security做用戶登錄的身份認證,配置完成後,spring security會幫我們驗證用戶身份。但是當我想給登錄頁面增加圖片驗證碼還能時,spring security的自動驗證機制讓我無從下手。

(1). 在/login的控制器中接收並校驗驗證碼,驗證成功方可登錄。事實是,spring security直接做了登錄驗證,我寫的控制器根本沒用。

(2). 根據某些博客的做法,嘗試繼承UsernamePasswordAuthenticationFilter和DaoAuthenticationProvider,最終也失敗了。

最終我想到了使用失焦事件驗證的辦法:當文本框失去焦點的時,前端頁面發送ajax請求給後臺校驗驗證碼,並在頁面設置一個隱藏的input標籤來存儲校驗結果。點擊登錄按鈕時去讀取這個input標籤,如果失敗,則提示驗證碼錯誤,拒絕發起登錄請求。這樣就沒spring security什麼事了。

1、生成圖片驗證碼和校驗驗證碼的controller:

import com.github.bingoohuang.patchca.custom.ConfigurableCaptchaService;
import com.github.bingoohuang.patchca.filter.FilterFactory;
import com.github.bingoohuang.patchca.filter.predefined.*;
import com.github.bingoohuang.patchca.utils.encoder.EncoderHelper;
import com.ufclub.entity.common.MsgResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Controller
@RequestMapping("/yzm")
public class ValidateController {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private static ConfigurableCaptchaService cs = CaptchaFactory.getInstance();

    private static List<FilterFactory> factories;

    static {
        factories = new ArrayList<>();
        factories.add(new CurvesRippleFilterFactory(cs.getColorFactory()));
        factories.add(new MarbleRippleFilterFactory());
        factories.add(new DoubleRippleFilterFactory());
        factories.add(new WobbleRippleFilterFactory());
        factories.add(new DiffuseRippleFilterFactory());
    }

    @RequestMapping("/getImage")
    public void getImage(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        try {
            cs.setFilterFactory(factories.get(new Random().nextInt(5)));
            setResponseHeaders(response);

            String token = EncoderHelper.getChallangeAndWriteImage(cs, "png",
                    response.getOutputStream());
            session.setAttribute("TEST_YZM", token);
            logger.info("當前的SessionID = " + session.getId() + ",  驗證碼 = " + token);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @ResponseBody
    @RequestMapping(value = "/verification")
    public MsgResponse validate(HttpServletRequest request, String verifyCode) {
        MsgResponse msgResponse = new MsgResponse();
        if(verifyCode != null){
            String yzm = (String) request.getSession().getAttribute("TEST_YZM");
            if(verifyCode.equals(yzm))
                msgResponse.setSuccess(true);
        }
        return msgResponse;
    }

    private void setResponseHeaders(HttpServletResponse response) {
        response.setContentType("image/png");
        response.setHeader("Cache-Control", "no-cache, no-store");
        response.setHeader("Pragma", "no-cache");
        long time = System.currentTimeMillis();
        response.setDateHeader("Last-Modified", time);
        response.setDateHeader("Date", time);
        response.setDateHeader("Expires", time);
    }

}
CaptchaFactory的代碼:

import com.github.bingoohuang.patchca.color.RandomColorFactory;
import com.github.bingoohuang.patchca.custom.ConfigurableCaptchaService;
import com.github.bingoohuang.patchca.word.RandomWordFactory;

public class CaptchaFactory {

    private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService();

    static {
        cs.setColorFactory(new RandomColorFactory());
        RandomWordFactory wf = new RandomWordFactory();
        wf.setCharacters("1234567890");
        wf.setMaxLength(4);
        wf.setMinLength(4);
        cs.setWordFactory(wf);
    }

    public static ConfigurableCaptchaService getInstance() {
        return cs;
    }
}
2、前端頁面:

<form name="loginForm" id="loginForm" th:action="@{/login}" method="post">
	<fieldset>
		<label class="block clearfix">
			<span class="block input-icon input-icon-right">
				<input type="text" name="username" id="username" class="form-control" placeholder="用戶名" />
				<i class="icon-user"></i>
			</span>
		</label>

		<label class="block clearfix">
			<span class="block input-icon input-icon-right">
				<input type="password" name="password" id="password" class="form-control" placeholder="密碼" />
				<i class="icon-lock"></i>
			</span>
		</label>

		<div th:height="34px">
			<input type="text" name="verifyCode" id="verifyCode" placeholder="請輸入驗證碼" th:onblur="'checkVerifyCode()'"/>
			<input type="hidden" id="verifyStatus" />
			<img src="/yzm/getImage" id="reloadImage" th:width="100px" th:height="28px"/>
			<!--<a href="javaScript:;" id="changeImage" th:width="100px">換一張</a>-->
		</div>

		<div class="space-2"></div>

		<div class="clearfix">
			<div th:if="${param.error}">
				<div class="btn btn-xs btn-danger">
					<i class="icon-bolt bigger-110"></i>
					用戶名或密碼不正確!
				</div>
			</div>
		</div>

		<div class="clearfix">
			<label class="inline">
				<input type="checkbox" id="remember-me" name="remember-me" class="ace" />
				<span class="lbl"> 自動登錄</span>
			</label>
			<input type="button" class="width-35 pull-right btn btn-sm btn-primary" value="登錄" th:onclick="'submitLoginForm()'"/>
		</div>
		<div class="space-4"></div>
	</fieldset>
</form>
js代碼:

function checkVerifyCode() {
	var verifyCode = $("#verifyCode").val();
	if(verifyCode == "")
		return;
	$.ajax({
		type: "POST",
		url: "/yzm/verification",
		data: {
			"verifyCode": verifyCode
		},
		dataType:"json",
		success:function(data){
			if(data.success){
				$("#verifyStatus").val('true');
//				layer.tips('驗證碼正確','#reloadImage', {tips: [2,'#D15B47']});
			}else{
				$("#verifyStatus").val('false');
				layer.tips('驗證碼錯誤','#reloadImage', {tips: [2,'#D15B47']});
			}
		},
		error:function (XMLHttpRequest, textStatus) {
			layer.msg("[" + textStatus + "]" + "系統錯誤,請聯繫管理員", {time : 2500}, function(){});
		}
	});
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章