轉載自 : www.javaman.cn
該工具類主要生成從0-9,a-z,A-Z範圍內產生的4位元亂數
/**
* 產生4位元隨機字串
*/
public static String getCheckCode() {
String base = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int size = base.length();
Random r = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 1; i <= 4; i++) {
//產生0到size-1的隨機值
int index = r.nextInt(size);
//在base字串中獲取下標為index的字元
char c = base.charAt(index);
//將c放入到StringBuffer中去
sb.append(c);
}
return sb.toString();
}
使用者常數的繫結,所有的常數都可以在ConfigConsts中定義,方便管理。
import java.util.Arrays;
import java.util.List;
public interface ConfigConsts {
/**
* 驗證碼存session
*/
String IMAGE_CODE_SESSION = "IMAGE_CODE";
}
這段程式碼的主要作用是為使用者生成一個圖片驗證碼,並將其顯示在瀏覽器中。當呼叫該程式碼對應的URL時,伺服器會建立一個包含隨機驗證碼的圖片,並將此驗證碼儲存在使用者的對談中,然後將該圖片傳送給使用者的瀏覽器顯示
/**
* 驗證碼
*/
@RequestMapping("/getImgCode")
public void getImgCode(HttpServletRequest request, HttpServletResponse response) {
int width = 80;
int height = 30;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//獲取畫筆
Graphics graphics = image.getGraphics();
//設定畫筆顏色為白色
graphics.setColor(Color.white);
//填充圖片
graphics.fillRect(0, 0, width, height);
//設定畫筆顏色為黑色
graphics.setColor(Color.black);
//設定字型的小大
graphics.setFont(new Font("黑體", Font.BOLD, 24));
//產生4個隨機驗證碼
String checkCode = CommonUtil.getCheckCode();
//將驗證碼放入HttpSession中
HttpSession session = request.getSession();
session.setAttribute(ConfigConsts.IMAGE_CODE_SESSION, checkCode);
//向圖片上寫入驗證碼
graphics.drawString(checkCode, 15, 25);
//將記憶體中的圖片輸出到瀏覽器
try {
response.setContentType("image/png");
ImageIO.write(image, "PNG", response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
對「/loginPage」的GET請求,並將使用者重定向到登入頁面。當呼叫這個URL時,系統會返回一個名為"login"的檢視(通常是一個HTML頁面),這個檢視通常用於顯示登入表單,讓使用者輸入使用者名稱和密碼等資訊。
/**
* 跳轉到登陸頁面
* @return 登陸頁面
*/
@GetMapping("/loginPage")
public String loginPage(){
return "login";
}
在Web頁面上實現一個圖形驗證碼的輸入功能
getImgCode
函數載入驗證碼圖片,並渲染表單。getImgCode
函數通過Ajax請求從伺服器獲取驗證碼圖片,並將其顯示在頁面上的圖片元素中。這段程式碼主要利用了layui框架來實現頁面的佈局和互動,同時通過JavaScript和Ajax實現與伺服器的通訊,以獲取並顯示圖形驗證碼。
<div class="layui-form-item">
<div class="layui-row">
<div class="layui-col-xs7">
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode"></label>
<input type="text" name="code" lay-verify="required" placeholder="圖形驗證碼" class="layui-input">
</div>
<div class="layui-col-xs5">
<div style="margin-left: 10px;">
<img id="codeImg" class="layadmin-user-login-codeimg">
</div>
</div>
</div>
<script>
layui.config({
base: '/static/layuiadmin/' //靜態資源所在路徑
}).extend({
index: 'lib/index' //主入口模組
}).use(['index', 'user'], function(){
let $ = layui.$,
form = layui.form;
// 初始化
getImgCode();
form.render();
}
/**
* 獲取驗證碼
*/
function getImgCode() {
let url = ctx + '/getImgCode';
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.onload = function() {
if (this.status === 200) {
let blob = this.response;
document.getElementById("codeImg").src = window.URL.createObjectURL(blob);
}
}
xhr.send();
}
</script>
校驗驗證碼的過濾器,基於Java的Spring框架。
OncePerRequestFilter
,確保每次請求只被過濾一次。doFilterInternal
方法中,它首先檢查請求是否是登入請求(通過檢查請求路徑是否為"/login"以及請求方法是否為"POST")。validate
方法來校驗驗證碼。validate
方法從請求中獲取驗證碼,然後與對談中儲存的驗證碼進行比對。如果驗證碼不存在、為空或不匹配,將丟擲異常。filterChain.doFilter
)。@Component
public class ValidateCodeFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
// 登陸請求
if ("/login".equals(httpServletRequest.getServletPath()) &&
"POST".equalsIgnoreCase(httpServletRequest.getMethod())){
try {
validate(httpServletRequest);
} catch (Exception exception) {
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write(JSON.toJSONString(Result.failure(exception.getMessage())));
writer.flush();
return;
}
}
// 不是一個登入請求,不做校驗 直接通過
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private void validate(HttpServletRequest request) {
String code = request.getParameter("code");
if (StringUtils.isBlank(code)){
throw new RuntimeException("驗證碼不能為空");
}
Object checkCode = request.getSession(false).getAttribute(ConfigConsts.IMAGE_CODE_SESSION);
if (Objects.isNull(checkCode)) {
throw new RuntimeException("驗證碼不存在");
}
if (!StringUtils.equalsIgnoreCase(code,checkCode.toString())) {
throw new RuntimeException("驗證碼不匹配");
}
request.getSession(false).removeAttribute(ConfigConsts.IMAGE_CODE_SESSION);
}
}
整合Spring Security的安全設定類,用於Web應用的安全性設定。
@EnableWebSecurity
和@Configuration
註解,啟用並設定Spring Security。@EnableGlobalMethodSecurity(prePostEnabled = true)
來啟用全域性方法級別的安全性,允許使用例如@PreAuthorize
和@PostAuthorize
等註解。MySecurityConfig
的設定類,該類繼承自WebSecurityConfigurerAdapter
,用於客製化安全性設定。@Autowired
注入了一個名為validateCodeFilter
的驗證碼過濾器範例。configure(HttpSecurity http)
方法中,對應用的安全性進行了詳細設定:
/loginPage
和/getImgCode
這兩個路徑,不進行任何安全檢查。validateCodeFilter
),用於在登入過程中校驗驗證碼。這段程式碼的主要目的是增強Web應用的安全性,通過新增驗證碼校驗來防止自動化登入嘗試和暴力破解,並限制了只有經過身份驗證的使用者才能存取應用的受保護資源。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ValidateCodeFilter validateCodeFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 放過
.antMatchers("/loginPage", "/getImgCode").permitAll()
.anyRequest().authenticated()
.and()
// 過濾登入驗證碼
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
}
執行結果如下: