目錄
項目地址:鏈接:https://pan.baidu.com/s/106lZU8P9gHG4A3aP4OpOgQ
提取碼:xs3v
實現圖片驗證碼功能
開發生成圖片驗證碼接口
用來封裝image圖片
public class ImageCode extends ValidateCode {
private BufferedImage image;
public ImageCode(BufferedImage image, String code, int expireIn){
super(code, expireIn);
this.image = image;
}
public ImageCode(BufferedImage image, String code, LocalDateTime expireTime){
super(code, expireTime);
this.image = image;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
}
將生成的圖片放入到session裏面
生成圖形驗證碼
/**
* 系統配置
*/
@Autowired
private SecurityProperties securityProperties;
/*
* (non-Javadoc)
*
* @see
* com.imooc.security.core.validate.code.ValidateCodeGenerator#generate(org.
* springframework.web.context.request.ServletWebRequest)
*/
@Override
public ImageCode generate(ServletWebRequest request) {
int width = ServletRequestUtils.getIntParameter(request.getRequest(), "width",
securityProperties.getCode().getImage().getWidth());
int height = ServletRequestUtils.getIntParameter(request.getRequest(), "height",
securityProperties.getCode().getImage().getHeight());
//生成圖片對象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//生成圖片對象
Graphics g = image.getGraphics();
//生成干擾條紋
Random random = new Random();
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
//生成干擾條紋
//生成四位隨機數
String sRand = "";
for (int i = 0; i < securityProperties.getCode().getImage().getLength(); i++) { //securityProperties.getCode().getImage().getLength() 生成條形碼的長度
String rand = String.valueOf(random.nextInt(10));
sRand += rand;
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
g.drawString(rand, 13 * i + 6, 16);
}
//生成四位隨機數
g.dispose();
return new ImageCode(image, sRand, securityProperties.getCode().getImage().getExpireIn()); //securityProperties.getCode().getImage().getExpireIn()過期時間
}
/**
* 生成隨機背景條紋
*
* @param fc
* @param bc
* @return
*/
private Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
public SecurityProperties getSecurityProperties() {
return securityProperties;
}
public void setSecurityProperties(SecurityProperties securityProperties) {
this.securityProperties = securityProperties;
}
將該請求加入到安全配置裏面
啓動之後
當圖片驗證碼發送給security框架之後,我們需要手動寫security過濾器來處理圖形驗證碼
創建過濾類ValidateCodeFilter繼承OncePerRequestFilter(使得只過濾一次)
將自己寫的過濾器加入的security過濾器鏈中
運行
代碼重構
驗證碼基本參數可配置
首先配置core項目中的屬性ImageCodeProperties
創建ValidateCodeProperties來封裝各個屬性類型(後期還會有短信驗證)
進入到demo項目中寫應用級的配置
請求級的配置
core項目中的ValidateCodeController對象
啓動項目指揮,請求裏面的width會覆蓋配置裏面的width,配置裏面的width會覆蓋默認的width
驗證碼攔截的接口可配置
將url進行統一處理
這樣的話,直接訪問user user/*的路徑都會被攔截下來,並且返回報錯信息
驗證碼的生成邏輯可配置
其實ImageCodeGenerator類也可以 @component註解直接注入,但是通過配置類註解來來創建實現,這樣的話可以通過@ConditionalOnMissingBean進行判斷是否bean裏面已經存在一個相同的bean
如果在其他地方又注入了它的話,這個時候上面的imageCodeGenerator就會失效
記住我
記住我基本原理
瀏覽器發送認證請求給後臺,當UsernamePasswordAuthenticationFilter認證成功之後通過RemenberMeService將token信息保存到TokenRepositoty以及數據庫中,然後將token寫入到瀏覽器Cookie中;
當瀏覽器過了幾天再次發送服務請求的時候,直接被RemenberMeAuthenticationFilter攔截下來,讀取Cookie中的token,在調用RemeberMeService去數據庫查找Token,調用UserDetailsService完成認證。
RememberMeAuthenticationFilter過濾器一般都在自定義過濾器的末尾,當前面的認證都不可行的時候,就嘗試的調用它
代碼實現
創建persistentTokenRepository的bean,用來調用數據庫驗證使用的。tokenRepository.setCreateTableOnStartup(true)方法的目的是第一次初始化的時候,在數據庫創建對象的表來存放token。
配置過期時間
調用userDetailsService
總體邏輯就是調用persistenTokenRepository()方法,去數據庫去或者存放對應的token,設置過期時間,然後調用userDetailsService驗證加載用戶信息。
記住我源碼分析
登陸
進入到UsernamePasswordAuthenticationFilter類中
認證成功之後,進入到AbstractAuthenticationProcessingFilter方法中
調用rememberMeServices
調用tokenRepository向數據庫添加新的token
addCookie()的方法就是將token寫到瀏覽器cookie裏面
服務重新啓動
判斷前面的認證是否認證成功,如果沒有認證成功就進入if語句
通過tokenSeries去數據庫拿token的值 ,然後就是做token的相關檢查
然後就是調用userDetailsService,去獲取用戶信息
認證成功之後,將認證信息保存到session裏面