自己在做項目的時候總結的配置全部流程,用作記錄也希望能幫助大家。
一、進行kaptha的依賴配置
1 <!--驗證碼生成工具--> 2 <dependency> 3 <groupId>com.github.penggle</groupId> 4 <artifactId>kaptcha</artifactId> 5 <version>2.3.2</version> 6 </dependency>
二、web.xml配置,我們只需要簡單配置一個 Servlet,頁面通過 IMG 標簽就可以展現圖形驗證碼。
<servlet> <servlet-name>Kaptcha</servlet-name> <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class> <init-param> <param-name>kaptcha.image.width</param-name> <param-value>200</param-value> </init-param> <init-param> <param-name>kaptcha.image.height</param-name> <param-value>50</param-value> </init-param> <init-param> <param-name>kaptcha.textproducer.char.length</param-name> <param-value>4</param-value> </init-param> <init-param> <param-name>kaptcha.noise.impl</param-name> <param-value>com.google.code.kaptcha.impl.NoNoise</param-value> </init-param> <init-param> <param-name>kaptcha.session.key</param-name> <param-value>rand</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Kaptcha</servlet-name> <url-pattern>/kaptcha.jpg</url-pattern> </servlet-mapping>
三、擴展 UsernamePasswordTokenShiro 表單認證,頁面提交的用戶名密碼等信息,用 UsernamePasswordToken 類來接收,很容易想到,要接收頁面驗證碼的輸入,我們需要擴展此類:
package com.caa.shiro.filter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; public class CaptchaUsernamePasswordToken extends UsernamePasswordToken { //驗證碼字符串 private String captcha; public CaptchaUsernamePasswordToken(String username, String password, boolean rememberMe, String captcha) { super(username, password, rememberMe); this.captcha = captcha; } public String getCaptcha() { return captcha; } public void setCaptcha(String captcha) { this.captcha = captcha; } }
四、
擴展 FormAuthenticationFilter
接下來我們擴展 FormAuthenticationFilter 類
這里貼一個全部的擴展方法,不過實際上我使用的是shiro自帶的登錄驗證 后添加的驗證碼的校驗方法(如果也是只需要添加驗證碼功能那只需要在你的控制層調用doCaptchaValidate方法即可
package com.caa.shiro.filter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CaptchaFormAuthenticationFilter extends FormAuthenticationFilter { private static final Logger LOG = LoggerFactory.getLogger(CaptchaFormAuthenticationFilter.class); public CaptchaFormAuthenticationFilter() { } @Override /** * 登錄驗證 */ protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { CaptchaUsernamePasswordToken token = createToken(request, response); try { /*圖形驗證碼驗證*/ doCaptchaValidate((HttpServletRequest) request, token); Subject subject = getSubject(request, response); subject.login(token);//正常驗證 LOG.info(token.getUsername()+"登錄成功"); return onLoginSuccess(token, subject, request, response); }catch (AuthenticationException e) { LOG.info(token.getUsername()+"登錄失敗--"+e); return onLoginFailure(token, e, request, response); } } // 驗證碼校驗 public void doCaptchaValidate(HttpServletRequest request, CaptchaUsernamePasswordToken token) { //session中的圖形碼字符串 HttpSession session = request.getSession(); String captcha = (String)session.getAttribute("rand"); //比對 if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptcha())) { throw new IncorrectCaptchaException("驗證碼錯誤!"); } } @Override protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String captcha = getCaptcha(request); boolean rememberMe = isRememberMe(request); String host = getHost(request); return new CaptchaUsernamePasswordToken(username, password, rememberMe, captcha); } public static final String DEFAULT_CAPTCHA_PARAM = "captcha"; private String captchaParam = DEFAULT_CAPTCHA_PARAM; public String getCaptchaParam() { return captchaParam; } public void setCaptchaParam(String captchaParam) { this.captchaParam = captchaParam; } protected String getCaptcha(ServletRequest request) { return WebUtils.getCleanParam(request, getCaptchaParam()); } //保存異常對象到request @Override protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) { request.setAttribute(getFailureKeyAttribute(), ae); } }
六、前面驗證碼校驗不通過,我們拋出一個異常 IncorrectCaptchaException,此類繼承 AuthenticationException,之所以需要擴展一個新的異常類,為的是在頁面能更精准顯示錯誤提示信息。
package com.caa.shiro.filter; import org.apache.shiro.authc.AuthenticationException; public class IncorrectCaptchaException extends AuthenticationException { /** * */ private static final long serialVersionUID = 1L; public IncorrectCaptchaException() { super(); } public IncorrectCaptchaException(String message, Throwable cause) { super(message, cause); } public IncorrectCaptchaException(String message) { super(message); } public IncorrectCaptchaException(Throwable cause) { super(cause); } }
七、shiro配置(Filter的配置及使用)這段因為我的配置文件東西較多 在網上貼了一段 核心東西都有
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"> <!-- Shiro Filter 攔截器相關配置 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- securityManager --> <property name="securityManager" ref="securityManager" /> <!-- 登錄路徑 --> <property name="loginUrl" value="/login.jsp" /> <!-- 登錄成功后跳轉路徑 --> <property name="successUrl" value="/pages/index.jsp" /> <!-- 授權失敗跳轉路徑 --> <property name="unauthorizedUrl" value="/login.jsp" /> <property name="filters"> <util:map> <entry key="authc" value-ref="myAuthenFilter" /> </util:map> </property> <!-- 過濾鏈定義 --> <property name="filterChainDefinitions"> <value> /login.jsp = authc /pages/* = authc /index.jsp* = authc /logout.do = logout <!-- 訪問這些路徑必須擁有某種權限 /role/edit/* = perms[role:edit] /role/save = perms[role:edit] /role/list = perms[role:view] --> </value> </property> </bean> <!-- 自定義驗證攔截器 --> <bean id="myAuthenFilter" class="javacommon.shiro.CaptchaFormAuthenticationFilter" /> <!-- securityManager --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm" /> </bean> <!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- 自定義Realm實現 --> <bean id="myRealm" class="javacommon.shiro.CustomRealm"> <!-- <property name="cacheManager" ref="shiroCacheManager" /> --> </bean> </beans>
八、前台頁面(本人用的是html加vue的,不過前天東西不多可以根據自己的頁面來修改)
<body class="hold-transition login-page" style="background: black url(statics/images/login-bg.jpg) no-repeat fixed top;"> <div class="login-box" id="rrapp" style="margin-top: 12%" v-cloak> <div class="login-box-body"> <p class="login-box-msg" style="font-size: 25px;font-weight:bold">中拍協后台管理系統</p> <div v-if="error" class="alert alert-danger alert-dismissible"> <h4 style="margin-bottom: 0px;"><i class="fa fa-exclamation-triangle"></i> {{errorMsg}}</h4> </div> <div class="form-group has-feedback"> <input type="text" class="form-control" v-model="username" @keyup.enter="login" placeholder="賬號" autofocus> <span class="fa fa-user form-control-feedback"></span> </div> <div class="form-group has-feedback"> <input type="password" class="form-control" v-model="password" @keyup.enter="login" placeholder="密碼"> <span class="fa fa-lock form-control-feedback"></span> </div> <div > <input type="text" id="code" name="captcha" v-model="captcha" @keyup.enter="login" class="form-control" placeholder="驗證碼"> </div> <div > <img id="codeImg" src="kaptcha.jpg" class="img-responsive" style="display:inline" @click="refreshCaptcha">(看不清<a href="javascript:void(0)" @click="refreshCaptcha" style="display:inline">換一張</a>) </div> <div class="checkbox"> <label> <input type="checkbox" name="isRememberMe" v-model="isRememberMe">記住我,下次免登陸 </label> </div> <div class="row"> <div class="col-xs-12"> <button type="button" class="btn btn-block btn-success btn-lg" @click="login">登錄</button> </div> </div> </div> </div> <script type="text/javascript"> var vm = new Vue({ el:'#rrapp', data:{ username: '', password: '', captcha: '', error: false, errorMsg: '', isRememberMe:false }, beforeCreate: function(){ if(self != top){ top.location.href = self.location.href; } }, methods: { login: function (event) { var data = "username="+vm.username+"&password="+vm.password+"&isRememberMe="+vm.isRememberMe+"&captcha="+vm.captcha; $.ajax({ type: "POST", url: "login", data: data, dataType: "json", success: function(result){ if(result.code == 0){//登錄成功 parent.location.href ='index.html'; }else{ vm.error = true; vm.errorMsg = result.msg; document.getElementById("codeImg").src="kaptcha.jpg?t=" + Math.random(); } } }); }, refreshCaptcha: function () { document.getElementById("codeImg").src="kaptcha.jpg?t=" + Math.random(); } } }); </script> </body>