发表于: 2020-01-09 18:53:28
1 1248
今天完成的事:
3.使用DES对用户ID和登录时间加密
加密一般分为对称加密和非对称加密,前者是我们加密之后可以使用方法再解密出来,而后者则是无法解密,如果想验证数据是否正确只能使用同样方法再次加密然后比较两次加密完生成的key是否相同。所以一般可以使用对称加密的地方都可以使用非对称加密,区别就是是否需要再解密出来。DES是对称加密.
可以使用DES来将用户的id和登录时间加密为uid和lid,存在cookie中,然后在拦截器中解密出来验证uid和lid的正确性,从而实现用户通行许可的验证。
首先编写一个DES加密的工具类(直接从网上复制就行),还有base64类,直接复制
在登录接口里验证登录→登录成功→对id和登录时间进行加密放在token中→创建cookie→把token放入cookie中
拦截器拦截cookie→看cookie是否为空→遍历cookie→看是否是否有token
DESUtil工具类直接再网上复制即可,还有base64
public class DESUtil {
/**
* 安全密钥
*/
private static String keyData = "ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstwxyz0123456789-_.";
//无参构造
public DESUtil() {
}
//有参构造
public DESUtil(String key) {
this.keyData = key;
}
/**
* 将Long类型加密
*
* @param source
* @return
* @throws UnsupportedEncodingException
*/
public String encryptFromLong(long source) throws UnsupportedEncodingException {
//先将long类型转化为String类型
String source1 = String.valueOf(source);
return encrypt(source1, "UTF-8");
}
/**
* 将解密好的转化为long类型
*
* @param encryptedData
* @return
* @throws UnsupportedEncodingException
*/
public long decryptToLong(String encryptedData) throws UnsupportedEncodingException {
long decryptLong = Long.valueOf(decrypt(encryptedData, "UTF-8"));
return decryptLong;
}
/**
* 加密UTF-8,调用底下的方法
*
* @param source 待加密数据
* @return 加密完成的数据
* @throws UnsupportedEncodingException 异常
*/
public static String encrypt(String source) throws UnsupportedEncodingException {
return encrypt(source, "UTF-8");
}
/**
* 解密UTF-8,调用底下的方法
*
* @param encryptedData 待解密数据
* @return 解密完成数据
* @throws UnsupportedEncodingException 异常
*/
public String decrypt(String encryptedData)
throws UnsupportedEncodingException {
return decrypt(encryptedData, "UTF-8");
}
/**
* 功能:加密
*
* @param source 待加密数据
* @param charSet 字符编码
* @return 加密完成数据
* @throws UnsupportedEncodingException 异常
*/
public static String encrypt(String source, String charSet)
throws UnsupportedEncodingException {
String encrypt = null;
byte[] ret = encrypt(source.getBytes(charSet));
encrypt = new String(Base64.encode(ret));
return encrypt;
}
/**
* 功能:解密
*
* @param encryptedData 待解密数据
* @param charSet 字符编码
* @return 解密完成数据
* @throws UnsupportedEncodingException 异常
*/
public String decrypt(String encryptedData, String charSet)
throws UnsupportedEncodingException {
String decryptedData = null;
// 有报错
byte[] ret = decrypt(Base64.decode(String.valueOf(encryptedData.toCharArray())));
decryptedData = new String(ret, charSet);
return decryptedData;
}
/**
* 加密
*
* @param primaryData
* @return
*/
private static byte[] encrypt(byte[] primaryData) {
//取得安全密钥
byte rawKeyData[] = getKey();
//DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
//使用原始密钥数据创建DESKeySpec对象
DESKeySpec dks = null;
try {
dks = new DESKeySpec(keyData.getBytes());
} catch (InvalidKeyException e) {
e.printStackTrace();
}
//创建一个密钥工厂
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//用密钥工厂把DESKeySpec转换成一个SecretKey对象
SecretKey key = null;
try {
key = keyFactory.generateSecret(dks);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
// Cipher对象实际完成加密操作
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
// 用密钥初始化Cipher对象
try {
cipher.init(Cipher.ENCRYPT_MODE, key, sr);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
// 正式执行加密操作
byte encryptedData[] = null;
try {
encryptedData = cipher.doFinal(primaryData);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
//返回加密数据
return encryptedData;
}
/**
* 加密
*
* @param encryptedData
* @return
*/
private byte[] decrypt(byte[] encryptedData) {
/** DES算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 取得安全密钥 */
byte rawKeyData[] = getKey();
/** 使用原始密钥数据创建DESKeySpec对象 */
DESKeySpec dks = null;
try {
dks = new DESKeySpec(keyData.getBytes());
} catch (InvalidKeyException e) {
e.printStackTrace();
}
/** 创建一个密钥工厂 */
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
/** 用密钥工厂把DESKeySpec转换成一个SecretKey对象 */
SecretKey key = null;
try {
key = keyFactory.generateSecret(dks);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
/** Cipher对象实际完成加密操作 */
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
/** 用密钥初始化Cipher对象 */
try {
cipher.init(Cipher.DECRYPT_MODE, key, sr);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
/** 正式执行解密操作 */
byte decryptedData[] = null;
try {
decryptedData = cipher.doFinal(encryptedData);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedData;
}
/**
* 获得密钥
*
* @return
*/
private static byte[] getKey() {
/** DES算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为我们选择的DES算法生成一个密钥生成器对象 */
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
kg.init(sr);
/** 生成密钥工具类 */
SecretKey key = kg.generateKey();
/** 生成密钥byte数组 */
byte rawKeyData[] = key.getEncoded();
return rawKeyData;
}
base64.class
public class Base64 {
public Base64() {
}
/**
* 编码字符串
*
* @param data 需要编码的字符串
* @return 编码完成的字符串
*/
public static String encode(String data) {
return new String(encode(data.getBytes()));
}
/**
* 解码字符串
*
* @param data 需要解码的字符串
* @return 解码完成的字符串
*/
public static String decode(String data) {
return new String(decode(data.toCharArray()));
}
/**
* 编码byte[]
*
* @param data 输入需要编码的字节组
* @return 编码完成的char类型数组
*/
public static char[] encode(byte[] data) {
char[] out = new char[((data.length + 2) / 3) * 4];
for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
boolean quad = false;
boolean trip = false;
int val = (0xFF & (int) data[i]);
val <<= 8;
if ((i + 1) < data.length) {
val |= (0xFF & (int) data[i + 1]);
trip = true;
}
val <<= 8;
if ((i + 2) < data.length) {
val |= (0xFF & (int) data[i + 2]);
quad = true;
}
out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 1] = alphabet[val & 0x3F];
val >>= 6;
out[index + 0] = alphabet[val & 0x3F];
}
return out;
}
/**
* 解码
*
* @param data
* @return
*/
public static byte[] decode(char[] data) {
int tempLen = data.length;
for (int ix = 0; ix < data.length; ix++) {
if ((data[ix] > 255) || codes[data[ix]] < 0) {
--tempLen;
}
}
int len = (tempLen / 4) * 3;
if ((tempLen % 4) == 3) {
len += 2;
}
if ((tempLen % 4) == 2) {
len += 1;
}
byte[] out = new byte[len];
// # of excess bits stored in accum
int shift = 0;
// excess bits
int accum = 0;
int index = 0;
// we now go through the entire array (NOT using the 'tempLen' value)
for (int ix = 0; ix < data.length; ix++) {
int value = (data[ix] > 255) ? -1 : codes[data[ix]];
// skip over non-code
if (value >= 0) {
// bits shift up by 6 each time thru
accum <<= 6;
// loop, with new bits being put in
shift += 6;
// at the bottom.
accum |= value;
// whenever there are 8 or more shifted in,
if (shift >= 8) {
// write them out (from the top, leaving any
shift -= 8;
// excess at the bottom for next iteration.
out[index++] =
(byte) ((accum >> shift) & 0xff);
}
}
}
// if there is STILL something wrong we just have to throw up now!
if (index != out.length) {
throw new Error("Miscalculated data length (wrote " + index
+ " instead of " + out.length + ")");
}
return out;
}
/**
* 编码文件
*
* @param file
* @throws IOException
*/
public static void encode(File file) throws IOException {
if (!file.exists()) {
System.exit(0);
} else {
byte[] decoded = readBytes(file);
char[] encoded = encode(decoded);
writeChars(file, encoded);
}
file = null;
}
/**
* 解码文件
*
* @param file
* @throws IOException
*/
public static void decode(File file) throws IOException {
if (!file.exists()) {
System.exit(0);
} else {
char[] encoded = readChars(file);
byte[] decoded = decode(encoded);
writeBytes(file, decoded);
}
file = null;
}
private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
.toCharArray();
private static byte[] codes = new byte[256];
static {
for (int i = 0; i < 256; i++) {
codes[i] = -1;
}
for (int i = 'A'; i <= 'Z'; i++) {
codes[i] = (byte) (i - 'A');
}
for (int i = 'a'; i <= 'z'; i++) {
codes[i] = (byte) (26 + i - 'a');
}
for (int i = '0'; i <= '9'; i++) {
codes[i] = (byte) (52 + i - '0');
}
codes['+'] = 62;
codes['/'] = 63;
}
/**
* 读取文件中的字符,转化为byte[]
*
* @param file
* @return
* @throws IOException
*/
private static byte[] readBytes(File file) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = null;
InputStream fis = null;
InputStream is = null;
try {
fis = new FileInputStream(file);
is = new BufferedInputStream(fis);
int count = 0;
byte[] buf = new byte[16384];
while ((count = is.read(buf)) != -1) {
if (count > 0) {
baos.write(buf, 0, count);
}
}
b = baos.toByteArray();
} finally {
try {
if (fis != null) {
fis.close();
}
if (is != null) {
is.close();
}
// if (baos != null)
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return b;
}
/**
* 读取文件中的字符,转化为char[]
*
* @param file
* @return
* @throws IOException
*/
private static char[] readChars(File file) throws IOException {
CharArrayWriter caw = new CharArrayWriter();
Reader fr = null;
Reader in = null;
try {
fr = new FileReader(file);
in = new BufferedReader(fr);
int count = 0;
char[] buf = new char[16384];
while ((count = in.read(buf)) != -1) {
if (count > 0) {
caw.write(buf, 0, count);
}
}
} finally {
try {
// if (caw != null)
caw.close();
if (in != null) {
in.close();
}
if (fr != null) {
fr.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return caw.toCharArray();
}
/**
* 将byte[]字符写入文件中
*
* @param file
* @param data
* @throws IOException
*/
private static void writeBytes(File file, byte[] data) throws IOException {
OutputStream fos = null;
OutputStream os = null;
try {
fos = new FileOutputStream(file);
os = new BufferedOutputStream(fos);
os.write(data);
} finally {
try {
if (os != null) {
os.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
System.out.println(e);
}
}
}
/**
* 将char[]字符写入文件中
*
* @param file
* @param data
* @throws IOException
*/
private static void writeChars(File file, char[] data) throws IOException {
Writer fos = null;
Writer os = null;
try {
fos = new FileWriter(file);
os = new BufferedWriter(fos);
os.write(data);
} finally {
try {
if (os != null) {
os.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
controller.class
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(User user,HttpServletResponse response, DESUtil desUtil) throws UnsupportedEncodingException {
// 如果能查出来数据,说明数据库里有这条数据,那么登录成功,跳转首页,否则登录失败,跳回登录页面
List<User> list = userService.selectByCondition(user.getName(), user.getPassword());
// DES加密
String str1 = desUtil.encryptFromLong(System.currentTimeMillis());
String str2 = desUtil.encryptFromLong(user.getId());
// token由用户名,id,登录时间组成
String token = desUtil.encrypt(str1+"|"+user.getName()+"|"+str2);
if (!CollectionUtils.isEmpty(list)) {
// 创建cookie对象,将登录信息存入里面
Cookie nameCookie = new Cookie("name", user.getName());
// 创建cookie对象,把token放进去
Cookie tokenCookie = new Cookie("token",token);
// 设置token的生命周期为30分钟
tokenCookie.setMaxAge(30*60);
// 设置cookie的生命周期30分钟
nameCookie.setMaxAge(30 * 60);
// 保存到客户端
response.addCookie(tokenCookie);
// 保存cookie到客户端
response.addCookie(nameCookie);
return "student";
} else {
return "login";
}
}
}
拦截器(就是判断用户登陆访问那个网页不登陆访问那个网页)
LoginInterceptor.class
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
// 请求Cookie里的信息,放入cookie里
Cookie[] cookie=httpServletRequest.getCookies();
if(cookie==null&&cookie.length==0){
System.out.println("cookie is null=================");
}else {
System.out.println("this is cookie================"+cookie);
for (Cookie cookies:cookie) {
if (cookies.getName().equals("name")){
System.out.println("name is =============="+cookies.getValue());
if (cookies.getName().equals("token")){
System.out.println("token is ================"+cookies.getValue());
}
return true;
}
}
}
httpServletResponse.sendRedirect("/login");
return false;
}
加密:
我们在用户模块,对于用户密码的保护,通常都会进行加密。从最简单来说,小明盗取了你的数据库信息,但由于你对你数据库中的用户信息的密码是加密的(我们假设加密之后的密文是无法破解的),那小明即使得到信息也没法进行登录。这是最最基本的一点防范措施。
用户在提交注册信息时,在后台的业务逻辑中将密码进行加密(使用MD5,或者BCrypt),所以存放在数据库中的信息为加密之后的密文。例如,如果小红在你的系统中注册了自己的账号,她提交的注册信息中的密码为”admin”,那么实际存到数据库中的密码为“21232F297A57A5A743894A0E4A801FC3”(假设采用MD5加密,并且不会被破解)。这样我们至少保证了只有小红本人能够通过其账号进行登录,因为密码只有她自己知道。当小红用其账号进行登录的过程中,她将自己的用户名和密码提交给后台的服务器,服务器得到密码之后,采用同样的加密方法(MD5加密),也会得到密文,这个时候再与数据库中的密码字段的数据进行字符串的比较,相同就代表验证通过。
加盐:
加盐是为了应对这么一种情况:如果两个人或多个人的密码相同,那么通过相同的加密算法得到的是相同的结果。这样会造成哪些后果呢?首先,破解一个就有可能是相当于破一片密码。而且加入小明这个用户可以查看后台数据库,那么如果他观察到小红这个用户的密码跟自己的密码是一样的(虽然都是密文),那么,也就代表他们两个人的密码是相同的。所以他就可以用小红的身份进行登录了。
其实,我们只要稍微混淆一下就能防范住了,这在加密术语中称为“加盐”。具体来说就是在原有材料(用户自定义密码)中加入其他成分(一般是用户自有且不变的因素),以此来增加系统复杂度。当这种盐和用户密码结合后,再通过摘要处理,就能得到隐蔽性更强的摘要值。
评论