防暴力破解的课题一直是信息安全的重点,漏洞攻击更是开发者的噩梦。。。。
如果没有经历过这个噩梦,请感受一下被信安部门支配的恐惧。(一大堆漏洞给扫出来,您修代码吧)
前端:HTML+JS+CSS 开源组件:Layui
后端:Java 后端框架:SpringBoot
思路:
手机模式看看效果:
用于生成滑动验证码的两个要素
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Random;
public class VerifyImageUtil {
/**
* 源文件宽度
*/
private static int ORI_WIDTH = 200;
/**
* 源文件高度
*/
private static int ORI_HEIGHT = 116;
/**
* 模板图宽度
*/
private static int CUT_WIDTH = 50;
/**
* 模板图高度
*/
private static int CUT_HEIGHT = 50;
/**
* 抠图凸起圆心
*/
private static int circleR = 5;
/**
* 抠图内部矩形填充大小
*/
private static int RECTANGLE_PADDING = 8;
/**
* 抠图的边框宽度
*/
private static int SLIDER_IMG_OUT_PADDING = 1;
/**
* 根据传入的路径生成指定验证码图片
*
* @param filePath
* @return
* @throws IOException
*/
public static VerifyImage getVerifyImage(String filePath) throws IOException {
BufferedImage srcImage = ImageIO.read(new File(filePath));
int locationX = CUT_WIDTH + new Random().nextInt(srcImage.getWidth() - CUT_WIDTH * 3);
int locationY = CUT_HEIGHT + new Random().nextInt(srcImage.getHeight() - CUT_HEIGHT) / 2;
BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
int[][] data = getBlockData();
cutImgByTemplate(srcImage, markImage, data, locationX, locationY);
return new VerifyImage(getImageBASE64(srcImage),getImageBASE64(markImage),locationX,locationY,srcImage.getWidth(),srcImage.getHeight());
}
/**
* 生成随机滑块形状
*
* 0 透明像素
* 1 滑块像素
* 2 阴影像素
* @return int[][]
*/
private static int[][] getBlockData() {
int[][] data = new int[CUT_WIDTH][CUT_HEIGHT];
Random random = new Random();
//(x-a)²+(y-b)²=r²
//x中心位置左右5像素随机
double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0 - 5 + random.nextInt(10);
//y 矩形上边界半径-1像素移动
double y1_top = RECTANGLE_PADDING - random.nextInt(3);
double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + random.nextInt(3);
double y1 = random.nextInt(2) == 1 ? y1_top : y1_bottom;
double x2_right = CUT_WIDTH - RECTANGLE_PADDING - circleR + random.nextInt(2 * circleR - 4);
double x2_left = RECTANGLE_PADDING + circleR - 2 - random.nextInt(2 * circleR - 4);
double x2 = random.nextInt(2) == 1 ? x2_right : x2_left;
double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + random.nextInt(10);
double po = Math.pow(circleR, 2);
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
//矩形区域
boolean fill;
if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING)
&& (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) {
data[i][j] = 1;
fill = true;
} else {
data[i][j] = 0;
fill = false;
}
//凸出区域
double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2);
if (d3 < po) {
data[i][j] = 1;
} else {
if (!fill) {
data[i][j] = 0;
}
}
//凹进区域
double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2);
if (d4 < po) {
data[i][j] = 0;
}
}
}
//边界阴影
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
//四个正方形边角处理
for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) {
//左上、右上
if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING
&& ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING)
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) {
data[i][j] = 2;
}
//左下、右下
if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) {
for (int n = 1; n <= SLIDER_IMG_OUT_PADDING; n++) {
if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING)
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) {
data[i][j] = 2;
}
}
}
}
if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) {
data[i][j - SLIDER_IMG_OUT_PADDING] = 2;
}
if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < CUT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PADDING] == 0) {
data[i][j + SLIDER_IMG_OUT_PADDING] = 2;
}
if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) {
data[i - SLIDER_IMG_OUT_PADDING][j] = 2;
}
if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDING][j] == 0) {
data[i + SLIDER_IMG_OUT_PADDING][j] = 2;
}
}
}
return data;
}
/**
* 裁剪区块
* 根据生成的滑块形状,对原图和裁剪块进行变色处理
* @param oriImage 原图
* @param targetImage 裁剪图
* @param blockImage 滑块
* @param x 裁剪点x
* @param y 裁剪点y
*/
private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) {
for (int i = 0; i < CUT_WIDTH; i++) {
for (int j = 0; j < CUT_HEIGHT; j++) {
int _x = x + i;
int _y = y + j;
int rgbFlg = blockImage[i][j];
int rgb_ori = oriImage.getRGB(_x, _y);
// 原图中对应位置变色处理
if (rgbFlg == 1) {
//抠图上复制对应颜色值
targetImage.setRGB(i,j, rgb_ori);
//原图对应位置颜色变化
oriImage.setRGB(_x, _y, Color.LIGHT_GRAY.getRGB());
} else if (rgbFlg == 2) {
targetImage.setRGB(i, j, Color.WHITE.getRGB());
oriImage.setRGB(_x, _y, Color.GRAY.getRGB());
}else if(rgbFlg == 0){
//int alpha = 0;
targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
}
}
}
}
/**
* 随机获取一张图片对象
* @param path
* @return
* @throws IOException
*/
public static BufferedImage getRandomImage(String path) throws IOException {
File files = new File(path);
File[] fileList = files.listFiles();
List fileNameList = new ArrayList<>();
if (fileList!=null && fileList.length!=0){
for (File tempFile:fileList){
if (tempFile.isFile() && tempFile.getName().endsWith(".jpg")){
fileNameList.add(tempFile.getAbsolutePath().trim());
}
}
}
Random random = new Random();
File imageFile = new File(fileNameList.get(random.nextInt(fileNameList.size())));
return ImageIO.read(imageFile);
}
/**
* 将IMG输出为文件
* @param image
* @param file
* @throws Exception
*/
public static void writeImg(BufferedImage image, String file) throws Exception {
byte[] imagedata = null;
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ImageIO.write(image,"png",bao);
imagedata = bao.toByteArray();
FileOutputStream out = new FileOutputStream(new File(file));
out.write(imagedata);
out.close();
}
/**
* 将图片转换为BASE64
* @param image
* @return
* @throws IOException
*/
public static String getImageBASE64(BufferedImage image) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image,"png",out);
//转成byte数组
byte[] bytes = out.toByteArray();
BASE64Encoder encoder = new BASE64Encoder();
//生成BASE64编码
//String showBase64 = encoder.encode(bytes);
String showBase64 = Base64.getEncoder().encodeToString(bytes);
// System.out.println("showBase64:\n"+showBase64+"\n");
return showBase64;
}
/**
* 将BASE64字符串转换为图片
* @param base64String
* @return
*/
public static BufferedImage base64StringToImage(String base64String) {
try {
BASE64Decoder decoder=new BASE64Decoder();
byte[] bytes1 = decoder.decodeBuffer(base64String);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);
return ImageIO.read(byteArrayInputStream);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
生成验证码的调用接口:/check/getImgSwipe
校验误差值的调用接口:/check/rstImgSwipe
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping(value = "/check")
public class UserController extends BaseController {
//获取滑动验证码的图片
@RequestMapping(value="/getImgSwipe",method=RequestMethod.GET)
@ResponseBody
public PageData getImgSwipe() {
PageData pd = new PageData();
String path = "";
int index = 0;
Random ran = new Random();
HttpSession session = this.getCurrentSession();
try {
session.setAttribute("imgSwipeSuccess","false");
//随机获取verifyImages文件夹下的某一张图片
String url = this.getClass().getResource("/").toString().substring(5);
String resources = "static/images/verifyImages";
path = url + resources;
File file = new File(path);
File [] files = file.listFiles();
index = ran.nextInt(files.length-1); //随机下标
System.out.println(files[index].getPath());
VerifyImage img = VerifyImageUtil.getVerifyImage(files[index].getPath());
pd.put("SrcImage",img.getSrcImage());
pd.put("CutImage",img.getCutImage());
// pd.put("XPosition",img.getXPosition());
pd.put("YPosition",img.getYPosition());
pd.put("SrcImageWidth",img.getSrcImageWidth());
pd.put("SrcImageHeight",img.getSrcImageHeight());
session.setAttribute("XPosition",img.getXPosition());
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pd;
}
//返回前端滑动验证码参数
@RequestMapping(value="/rstImgSwipe",method=RequestMethod.POST)
@ResponseBody
public PageData rstImgSwipe() {
PageData pd = this.getPageData();
Float moveEnd_X = Float.valueOf(pd.getString("moveEnd_X")) ;
Float wbili = Float.valueOf(pd.getString("wbili"));
HttpSession session = this.getCurrentSession();
Integer XPosition = Integer.parseInt(session.getAttribute("XPosition").toString());
Float xResult = XPosition * wbili;
System.out.println("mx:"+moveEnd_X+"\nmp:"+XPosition+"\nwbili:"+wbili+"\nxRst:"+xResult);
PageData pd1 = new PageData();
if(Math.abs(xResult-moveEnd_X)<10){ //设置误差像素
pd1.put("success",true);
session.setAttribute("imgSwipeSuccess","ture");
return pd1;
}else {
pd1.put("success",false);
session.setAttribute("imgSwipeSuccess","false");
return pd1;
}
}
}
document.write('');
layui.use(['layer', 'form', 'element'], function () {
window.layer = layui.layer;
window.form = layui.form;
window.element = layui.element;
});
var imgBase64 = ''
// 登陆前清空Session
sessionStorage.clear();
//图形验证码获取func
function VerifyImg(){
$.ajax({
url: "/check/getImg",
data: {},
cache:false,
type: "GET",
success: function (data) {
console.log(data)
imgBase64 = data["img"];
console.log(imgBase64);
document.getElementById("img").setAttribute("src","data:image/png;base64,"+imgBase64);
return imgBase64;
},
error: function(){
alert("error");
}
});
}
/*图形验证码获取与弹出*/
function layerVerifyCodeImg(userPhone){
// console.log(imgBase64);
layer.open({
id: 3,
offset: 'auto',
height:'200px',
type: 1,
title: '图形验证',
content:
''
+''
+''
,
//btn: ['确认'],
btnAlign: 'c', //按钮居中
success:function(){
$.ajax({
url: "/check/getImgSwipe",
data: {},
cache:false,
type: "GET",
// async:false,
success: function (data) {
console.log(data)
var SrcImage = "data:image/jpg;base64,"+data.SrcImage
var CutImage = "data:image/jpg;base64,"+data.CutImage
var YPosition = data.YPosition
var SrcImageWidth = data.SrcImageWidth;
var SrcImageHeight = data.SrcImageHeight;
//console.log(imgBase64);
imgVer({
el:'$("#imgVer")',
width:'220',
height:'116',
SrcImage:SrcImage,
CutImage:CutImage,
YPosition:YPosition,
SrcImageWidth:SrcImageWidth,
SrcImageHeight:SrcImageHeight,
userPhone:userPhone,
success:function () {
//验证成功可自定义后续逻辑
},
error:function () {
//alert('错误什么都不执行')
}
});
},
error: function(){
alert("error");
}
});
}
})
}
var InterValObj; //timer变量,控制时间
var count = 60; //间隔函数,1秒执行
var curCount = 0;//当前剩余秒数
/*短信验证码弹出层 */
function layerVerifyCode(phoneNumber) {
var phoneNumberDecode = phoneNumber;
// console.log(phoneNumberDecode);
var fillNum;
//判断是11位手机号码
if(checkLegal(phoneNumberDecode)){
fillNum = phoneNumberDecode;
}else{
fillNum='';
}
console.log(fillNum);
layer.open({
id: 2,
type: 1,
title: '请输入验证码',
area: ['auto', 'auto'],
content:
''
,
btn: ['确认'],
btnAlign: 'c', //按钮居中
btn1: function (index, layero) {
chcek_confirm();
}
})
//限制反复点击弹窗的按钮可用
if(curCount > 0){
$("#btnSendCode").attr("disabled", "true");
console.log('disabled');
}else if(curCount == 0){
console.log('enabled');
}else{
console.log('error');
}
}
/*发送验证码 */
function sendMessage() {
if(curCount == 0){
curCount = count; //设置button效果,开始计时,防止关闭重置
}
$("#btnSendCode").attr("disabled", "true");
$("#btnSendCode").val(curCount + "s");
InterValObj = window.setInterval(SetRemainTime, 1000); //启动计时器,1秒执行一次
var userPhone = $("#user_phone_verify").val();
/*向后台发送处理数据*/
console.log(userPhone);
$.ajax({
url: "/code/sendCode",
data: { MOBILE_NUMBER: encode(userPhone) },
type: "POST",
cache: false,
success: function (data) {
if (decode(data).success) {
layer.msg(decode(data).data);
} else {
layer.msg(decode(data).errorMessage);
}
}
})
}
/*timer处理函数*/
function SetRemainTime() {
if (curCount == 0) {
window.clearInterval(InterValObj);//停止计时器
$("#btnSendCode").removeAttr("disabled");//启用按钮
$("#btnSendCode").val("重新获取");
}
else {
curCount--;
$("#btnSendCode").val(curCount + "s");
}
}
function chcek_confirm () {
var phoneNumber = document.getElementById('user_phone_verify');
if (phoneNumber.value.length != 11) {
layer.alert("手机号不足11位");
} else if (!checkLegal(phoneNumber.value)) {
layer.alert("手机号输入不正确");
} else {
checkVerifyCode(phoneNumber.value,$("#user_verify").val());
}
}
function detectmob() {
if (navigator.userAgent.match(/Android/i)
|| navigator.userAgent.match(/webOS/i)
|| navigator.userAgent.match(/iPhone/i)
|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)
|| navigator.userAgent.match(/BlackBerry/i)
|| navigator.userAgent.match(/Windows Phone/i)
) {
return true;
}
else {
return false;
}
}
var userPhone
function imgVer(Config) {
userPhone = Config.userPhone
var el = eval(Config.el);
var w = Config.width;
var h = Config.height;
var SrcImage = Config.SrcImage
var CutImage = Config.CutImage
var YPosition = Config.YPosition
// var imgLibrary = Config.img;
var SrcImageHeight = Config.SrcImageHeight;
var SrcImageWidth = Config.SrcImageWidth;
var wbili = w / SrcImageWidth;
var hbili = h / SrcImageHeight;
console.log(wbili + '\n' + hbili);
var PL_Size = 48;
var padding = 20;
var MinN_X = padding + PL_Size;
var MaxN_X = w - padding - PL_Size - PL_Size / 6;
var MaxN_Y = padding;
var MinN_Y = h - padding - PL_Size - PL_Size / 6;
function RandomNum(Min, Max) {
var Range = Max - Min;
var Rand = Math.random();
if (Math.round(Rand * Range) == 0) {
return Min + 1;
} else if (Math.round(Rand * Max) == Max) {
return Max - 1;
} else {
var num = Min + Math.round(Rand * Range) - 1;
return num;
}
}
var imgSrc = SrcImage;
var X = '1';
var Y = '1';
console.log('PrintLocation');
console.log("X:" + X + "\n" + "Y:" + Y);
var left_Num = 0;
var html = '';
html += ' ';
html += '
';
html += ''; //设置触摸区域,防止左滑返回
html += '';
html += '按住左边滑块,拖动完成上方拼图
';
html += '';
html += '';
html += '';
el.html(html);
var c_l = document.getElementById("puzzleLost");
//var c_s = document.getElementById("puzzleShadow");
var ctx_l = c_l.getContext("2d");
//var ctx_s = c_s.getContext("2d");
var img = new Image();
img.src = CutImage;
img.onload = function () {
// ctx_l.drawImage(img, 0, YPosition);
ctx_l.drawImage(img, 0, YPosition * hbili, 50 * wbili, 50 * hbili);
}
var moveStart = '';
if (detectmob()) { //Mobile端
document.getElementsByClassName('slider-btn')[0].addEventListener("touchstart", function (e) {
e = e || window.event;
$(this).css({ "background-position": "0 -216px" });
moveStart = e.touches[0].pageX;
}, false);
var moveEnd;
document.addEventListener("touchmove", function (e) {
e = e || window.event;
var moveX = e.touches[0].pageX;
var d = moveX - moveStart;
if (moveStart == '') {
} else {
if (d < 0 || d > (w - 2 * padding)) {
} else {
$(".slider-btn").css({ "left": d + 'px', "transition": "inherit" });
$("#puzzleLost").css({ "left": d + 'px', "transition": "inherit" });
$("#puzzleShadow").css({ "left": d + 'px', "transition": "inherit" });
}
}
moveEnd = moveX
}, false);
document.addEventListener("touchend", function (e) {
e = e || window.event;
var moveEnd_X = moveEnd - moveStart;
if (moveStart == '') {
} else {
CheckResult_VerifyButton(moveEnd_X,wbili,Config);
}
setTimeout(function () {
$(".slider-btn").css({ "left": '0', "transition": "left 0.5s" });
$("#puzzleLost").css({ "left": '0', "transition": "left 0.5s" });
$("#puzzleShadow").css({ "left": '0', "transition": "left 0.5s" });
}, 1000);
$(".slider-btn").css({ "background-position": "0 -84px" });
moveStart = '';
Refresh_VerifyButton();
// console.log("mobile-refresh"); //mobile刷新
}, false)
} else { //PC端
$(".slider-btn").mousedown(function (e) {
e = e || window.event;
$(this).css({ "background-position": "0 -216px" });
moveStart = e.pageX;
});
var moveEnd;
onmousemove = function (e) {
e = e || window.event;
var moveX = e.pageX;
var d = moveX - moveStart;
if (moveStart == '') {
} else {
if (d < 0 || d > (w - 2 * padding)) {
} else {
$(".slider-btn").css({ "left": d + 'px', "transition": "inherit" });
$("#puzzleLost").css({ "left": d + 'px', "transition": "inherit" });
$("#puzzleShadow").css({ "left": d + 'px', "transition": "inherit" });
}
}
moveEnd = moveX
};
onmouseup = function (e) {
e = e || window.event;
var moveEnd_X = e.pageX - moveStart;
if (moveStart == '') {
} else {
CheckResult_VerifyButton(moveEnd_X,wbili,Config);
}
setTimeout(function () {
$(".slider-btn").css({ "left": '0', "transition": "left 0.5s" });
$("#puzzleLost").css({ "left": '0', "transition": "left 0.5s" });
$("#puzzleShadow").css({ "left": '0', "transition": "left 0.5s" });
}, 1000);
$(".slider-btn").css({ "background-position": "0 -84px" });
moveStart = '';
Refresh_VerifyButton();
// console.log("pc-refresh");
}
}
}
function CheckResult_VerifyButton(moveEnd_X,wbili,Config) {
$.ajax({
url: "/check/rstImgSwipe",
data: { moveEnd_X: encode(moveEnd_X), wbili: encode(wbili) },
type: "POST",
cache: false,
success: function (data) {
// var dataDecode = decode(data);
if (data.success) {
// console.log(data);
$(".ver-tips").html('验证通过');
$(".ver-tips").addClass("slider-tips");
$(".puzzle-lost-box").addClass("hidden");
$("#puzzleBox").addClass("hidden");
setTimeout(function () {
$(".ver-tips").removeClass("slider-tips");
imgVer(Config);
}, 2000);
Config.success();
} else {
// console.log(data);
$(".ver-tips").html('验证失败:拖动滑块将悬浮图像正确拼合');
$(".ver-tips").addClass("slider-tips");
setTimeout(function () {
$(".ver-tips").removeClass("slider-tips");
}, 2000);
// Config.error();
}
}
})
}
function Refresh_VerifyButton() {
$(".re-btn a").unbind('click').click(function () {
// imgVer(Config);
$.ajax({
url: "/check/getImgSwipe",
data: {},
cache: false,
type: "GET",
success: function (data) {
console.log(data)
var SrcImage = "data:image/jpg;base64," + data.SrcImage
var CutImage = "data:image/jpg;base64," + data.CutImage
var YPosition = data.YPosition
var SrcImageWidth = data.SrcImageWidth;
var SrcImageHeight = data.SrcImageHeight;
imgVer({
el: '$("#imgVer")',
width: '220',
height: '116',
SrcImage: SrcImage,
CutImage: CutImage,
YPosition: YPosition,
SrcImageWidth: SrcImageWidth,
SrcImageHeight: SrcImageHeight,
userPhone: userPhone,
success: function () {
//验证成功可自定义后续逻辑
}
});
},
error: function () {
alert("error");
}
});
})
}
xxxxxxx

.slider-btn{position:absolute;width:44px;height:44px;left:0;top:-7px;z-index:12;cursor:pointer;background-image:url(../images/checkSprite.png);background-position:0 -84px;transition:inherit}
.ver-tips{position:absolute;left:0;bottom:-22px;background:rgba(255,255,255,.9);height:22px;line-height:22px;font-size:12px;width:100%;margin:0;text-align:left;padding:0 8px;transition:all .4s}
.slider-tips{bottom:0}
.ver-tips i{display:inline-block;width:22px;height:22px;vertical-align:top;background-image:url(../images/checkSprite.png);background-position:-4px -1229px}
.ver-tips span{display:inline-block;vertical-align:top;line-height:22px;color:#455}
.active-tips{display:block}
.hidden{display:none}
.re-btn{position:absolute;left:0;bottom:0;height:28px;padding:0 16px}
.re-btn a{display:inline-block;width:14px;height:14px;margin:7px 0;background-image:url(../images/checkSprite.png);background-position:0 -1179px;cursor:pointer}
.re-btn a:hover{background-position:0 -1193px}
css里的图片checkSprite.png