shiro 和spring集合 實現登錄時輸入驗證碼並校驗(七)


編寫實現驗證碼的主體實現類:CaptchaCode

  1 import java.util.UUID;
  2 
  3 import javax.servlet.http.HttpServletRequest;
  4 import javax.servlet.http.HttpServletResponse;
  5 
  6 import org.apache.commons.lang3.StringUtils;
  7 import org.apache.shiro.cache.Cache;
  8 import org.apache.shiro.cache.CacheManager;
  9 import org.slf4j.Logger;
 10 import org.slf4j.LoggerFactory;
 11 import org.springframework.beans.factory.InitializingBean;
 12 import org.springframework.util.Assert;
 13 
 14 import com.itzixi.common.utils.CookieUtils;
 15 
 16 
 17 /**
 18  * 
 19  * @Title: CaptchaCode.java
 20  * @Description: 驗證碼實現類
 21  * @date 2017年10月14日 下午12:11:53
 22  * @version V1.0
 23  */
 24 public class CaptchaCode implements InitializingBean {
 25     private final static Logger logger = LoggerFactory.getLogger(CaptchaCode.class);
 26     private static final String DEFAULT_COOKIE_NAME = "itzixi-captcha";
 27     private final static String DEFAULT_CHACHE_NAME = "itzixiCaptchaCache";
 28     private final static int DEFAULT_MAX_AGE = -1; // cookie超時默認為session會話狀態
 29     
 30     private CacheManager cacheManager;
 31     private String cacheName;
 32     private String cookieName;
 33     
 34     private Cache<String, String> itzixiCaptchaCache;
 35     
 36     public CaptchaCode() {
 37         this.cacheName = DEFAULT_CHACHE_NAME;
 38         this.cookieName = DEFAULT_COOKIE_NAME;
 39     }
 40     
 41     public CaptchaCode(CacheManager cacheManager) {
 42         this();
 43         this.cacheManager = cacheManager;
 44     }
 45     
 46     public CacheManager getCacheManager() {
 47         return cacheManager;
 48     }
 49     
 50     public void setCacheManager(CacheManager cacheManager) {
 51         this.cacheManager = cacheManager;
 52     }
 53     
 54     public String getCacheName() {
 55         return cacheName;
 56     }
 57     
 58     public void setCacheName(String cacheName) {
 59         this.cacheName = cacheName;
 60     }
 61     
 62     public String getCookieName() {
 63         return cookieName;
 64     }
 65 
 66     public void setCookieName(String cookieName) {
 67         this.cookieName = cookieName;
 68     }
 69     
 70     @Override
 71     public void afterPropertiesSet() throws Exception {
 72         Assert.notNull(cacheManager, "cacheManager must not be null!");
 73         Assert.hasText(cacheName, "cacheName must not be empty!");
 74         Assert.hasText(cookieName, "cookieName must not be empty!");
 75         this.itzixiCaptchaCache = cacheManager.getCache(cacheName);
 76     }
 77     
 78     /**
 79      * 生成驗證碼
 80      */
 81     public void generate(HttpServletRequest request, HttpServletResponse response) {
 82         // 先檢查cookie的uuid是否存在
 83         String cookieValue = CookieUtils.getCookieValue(request, cookieName);
 84         boolean hasCookie = true;
 85         if (StringUtils.isBlank(cookieValue)) {
 86             hasCookie = false;
 87             cookieValue = UUID.randomUUID().toString();
 88         }
 89         String captchaCode = CaptchaUtils.generateCode().toUpperCase();// 轉成大寫重要
 90         // 不存在cookie時設置cookie
 91         if (!hasCookie) {
 92             CookieUtils.setCookie(request, response, cookieName, cookieValue, DEFAULT_MAX_AGE);
 93         }
 94         // 生成驗證碼
 95         CaptchaUtils.generate(response, captchaCode);
 96         itzixiCaptchaCache.put(cookieValue, captchaCode);
 97     }
 98     
 99     /**
100      * 僅能驗證一次,驗證后立即刪除
101      * @param request HttpServletRequest
102      * @param response HttpServletResponse
103      * @param userInputCaptcha 用戶輸入的驗證碼
104      * @return 驗證通過返回 true, 否則返回 false
105      */
106     public boolean validate(HttpServletRequest request, HttpServletResponse response, String userInputCaptcha) {
107         if (logger.isDebugEnabled()) {
108             logger.debug("validate captcha userInputCaptcha is " + userInputCaptcha);
109         }
110         String cookieValue = CookieUtils.getCookieValue(request, cookieName);
111         if (StringUtils.isBlank(cookieValue)) {
112             return false;
113         }
114         String captchaCode = itzixiCaptchaCache.get(cookieValue);
115         if (StringUtils.isBlank(captchaCode)) {
116             return false;
117         }
118         // 轉成大寫重要
119         userInputCaptcha = userInputCaptcha.toUpperCase();
120         boolean result = userInputCaptcha.equals(captchaCode);
121         if (result) {
122             itzixiCaptchaCache.remove(cookieValue);
123             CookieUtils.deleteCookie(request, response, cookieName);
124         }
125         return result;
126     }
127 }
CaptchaUtils.java
  1 import java.awt.BasicStroke;
  2 import java.awt.Color;
  3 import java.awt.Font;
  4 import java.awt.Graphics2D;
  5 import java.awt.RenderingHints;
  6 import java.awt.geom.QuadCurve2D;
  7 import java.awt.image.BufferedImage;
  8 import java.util.Random;
  9 
 10 import javax.imageio.ImageIO;
 11 import javax.servlet.ServletOutputStream;
 12 import javax.servlet.http.HttpServletResponse;
 13 
 14 /**
 15  * 
 16  * @Title: CaptchaUtils.java
 17  * @Description: 驗證碼工具類
 18  * @date 2017年10月14日 下午12:13:14
 19  * @version V1.0
 20  */
 21 class CaptchaUtils {
 22     // 默認的驗證碼大小
 23     private static final int WIDTH = 108, HEIGHT = 40, CODE_SIZE = 4;
 24     // 驗證碼隨機字符數組
 25     protected static final char[] charArray = "3456789ABCDEFGHJKMNPQRSTUVWXY".toCharArray();
 26     // 驗證碼字體
 27     private static final Font[] RANDOM_FONT = new Font[] {
 28         new Font("nyala", Font.BOLD, 38),
 29         new Font("Arial", Font.BOLD, 32),
 30         new Font("Bell MT", Font.BOLD, 32),
 31         new Font("Credit valley", Font.BOLD, 34),
 32         new Font("Impact", Font.BOLD, 32),
 33         new Font(Font.MONOSPACED, Font.BOLD, 40)
 34     };
 35     
 36     /**
 37      * 生成驗證碼
 38      */
 39     static void generate(HttpServletResponse response, String vCode) {
 40         BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
 41         response.setHeader("Pragma","no-cache");
 42         response.setHeader("Cache-Control","no-cache");
 43         response.setDateHeader("Expires", 0);
 44         response.setContentType("image/jpeg");
 45         
 46         ServletOutputStream sos = null;
 47         try {
 48             drawGraphic(image, vCode);
 49             sos = response.getOutputStream();
 50             ImageIO.write(image, "JPEG", sos);
 51             sos.flush();
 52         } catch (Exception e) {
 53             throw new RuntimeException(e);
 54         } finally {
 55             IOUtils.closeQuietly(sos);
 56         }
 57     }
 58     
 59     // 生成隨機類
 60     private static final Random RANDOM = new Random();
 61     
 62     /**
 63      * 生成驗證碼字符串
 64      * @return 驗證碼字符串
 65      */
 66     static String generateCode() {
 67         int count = CODE_SIZE;
 68         char[] buffer = new char[count];
 69         for (int i = 0; i < count; i++) {
 70             buffer[i] = charArray[RANDOM.nextInt(charArray.length)];
 71         }
 72         return new String(buffer);
 73     }
 74     
 75     private static void drawGraphic(BufferedImage image, String code){
 76         // 獲取圖形上下文
 77         Graphics2D g = image.createGraphics();
 78         g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
 79         // 圖形抗鋸齒
 80         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 81         // 字體抗鋸齒
 82         g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 83         
 84         // 設定背景色,淡色
 85         g.setColor(getRandColor(210, 250));
 86         g.fillRect(0, 0, WIDTH, HEIGHT);
 87         
 88         // 畫小字符背景
 89         Color color = null;
 90         for(int i = 0; i < 20; i++){
 91             color = getRandColor(120, 200);
 92             g.setColor(color);
 93             String rand = String.valueOf(charArray[RANDOM.nextInt(charArray.length)]);
 94             g.drawString(rand, RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
 95             color = null;
 96         }
 97         // 取隨機產生的認證碼(4位數字)
 98         char[] buffer = code.toCharArray();
 99         for (int i = 0; i < buffer.length; i++){
100             char _code = buffer[i];
101             //旋轉度數 最好小於45度
102             int degree = RANDOM.nextInt(28);
103             if (i % 2 == 0) {
104                 degree = degree * (-1);
105             }
106             //定義坐標
107             int x = 22 * i, y = 21;
108             //旋轉區域
109             g.rotate(Math.toRadians(degree), x, y);
110             //設定字體顏色
111             color = getRandColor(20, 130);
112             g.setColor(color);
113             //設定字體,每次隨機
114             g.setFont(RANDOM_FONT[RANDOM.nextInt(RANDOM_FONT.length)]);
115             //將認證碼顯示到圖象中
116             g.drawString("" + _code, x + 8, y + 10);
117             //旋轉之后,必須旋轉回來
118             g.rotate(-Math.toRadians(degree), x, y);
119         }
120         //圖片中間曲線,使用上面緩存的color
121         g.setColor(color);
122         //width是線寬,float型
123         BasicStroke bs = new BasicStroke(3);
124         g.setStroke(bs);
125         //畫出曲線
126         QuadCurve2D.Double curve = new QuadCurve2D.Double(0d, RANDOM.nextInt(HEIGHT - 8) + 4, WIDTH / 2, HEIGHT / 2, WIDTH, RANDOM.nextInt(HEIGHT - 8) + 4);
127         g.draw(curve);
128         // 銷毀圖像
129         g.dispose();
130     }
131 
132     /**
133      * 給定范圍獲得隨機顏色
134      */
135     private static Color getRandColor(int fc, int bc) {
136         if (fc > 255)
137             fc = 255;
138         if (bc > 255)
139             bc = 255;
140         int r = fc + RANDOM.nextInt(bc - fc);
141         int g = fc + RANDOM.nextInt(bc - fc);
142         int b = fc + RANDOM.nextInt(bc - fc);
143         return new Color(r, g, b);
144     }
145 }
IOUtils.java
 1 import java.io.Closeable;
 2 import java.io.IOException;
 3 
 4 /**
 5  * 
 6  * @Title: IOUtils.java
 7  * @Description: 流工具類,繼承自Spring
 8  * @date 2017年10月14日 下午12:13:04
 9  * @version V1.0
10  */
11 public class IOUtils extends org.springframework.util.StreamUtils {
12 
13     /**
14      * closeQuietly
15      * @param closeable 自動關閉
16      */
17     public static void closeQuietly(Closeable closeable) {
18         try {
19             if (closeable != null) {
20                 closeable.close();
21             }
22         } catch (IOException ioe) {
23             // ignore
24         }
25     }
26 }

2、增加Bean的配置文件 在spring配置文件中增加:並采用緩存redis實現驗證碼的緩存存儲

1 <!--此Bean 只是增加登錄時的驗證碼處理,不是shiro必須的配置-->
2     <bean class="com.itzixi.web.utils.CaptchaCode">
3         <!--<property name="cacheManager" ref="shiroEhcacheManager"/>-->
4         <property name="cacheManager" ref="shiroRedisCacheManager"></property>
5         <!-- 復用半小時緩存 -->
6         <property name="cacheName" value="cacheCaptcha"/>
7     </bean>

3、增加前端代碼實現:

 1  <div class="form-group">
 2             <label class="control-label visible-ie8 visible-ie9">密碼</label>
 3             <div id="input-error">
 4                 <input class="form-control form-control-solid placeholder-no-fix form-group" type="text"
 5                        autocomplete="off" placeholder="驗證碼" name="captcha" required/>
 6                 <a>
 7                     <img id="captcha" alt="驗證碼" src="<%=request.getContextPath() %>/captcha.action"
 8                          data-src="<%=request.getContextPath() %>/captcha.action?time="
 9                          style="width:94.5px;height:35px;"/>
10                 </a>
11             </div>
12         </div>

在Controller增加/captcha.action 服務地址方法,調用驗證碼生成類進行驗證碼生成並加入到緩存中去 

 

4、在Controller層增加代碼實現 接收,驗證動作,如:CenterController.doPostlogin(....)

 1  @RequestMapping(value = "/login", method = RequestMethod.POST)
 2     @ResponseBody
 3     public LeeJSONResult doPostlogin(String username, String password, String captcha,
 4                                      @RequestParam(value = "isRememberMe", defaultValue = "0") Integer isRememberMe,
 5                                      HttpServletRequest request, HttpServletResponse response) {
 6 
 7         if (StringUtils.isBlank(username)) {
 8             return LeeJSONResult.errorMsg("用戶名不能為空");
 9         }
10         if (StringUtils.isBlank(password)) {
11             return LeeJSONResult.errorMsg("密碼不能為空");
12         }
13         if (!captchaCode.validate(request, response, captcha)) {
14             return LeeJSONResult.errorMsg("驗證碼錯誤, 請重新輸入...");
15         }
16       return LeeJSONResult.ok();
17   }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM