简单的用户表设计如上图:
代码如下所示:
随机加密算法6个:
package com.auth.sp.common.utils;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import sun.misc.BASE64Encoder;
import java.security.Key;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* 作者: 薛俊鹏
* 时间:2018/10/15 on 17:12 .
* 描述:算法中心
* 内容:这里记录描述了N种需要密钥的算法
* 每种算法都会有一个特定的标识,根据标识锁定算法,最后在由MD5加密一次,加密的结果都保留大写
* 状态: 编写/修改
*/
public class AlgorithmCenter {
/**密钥算法**/
public static final String KEY_ALGORITHM = "AES";
/**加解密算法/工作模式/填充方式**/
public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 加密数据 ral=1
* @param data 待加密数据
* @param key 密钥 16位
* @return 加密后的数据
* */
public static String AESencrypt1(String data, String key) throws Exception {
Key k = new SecretKeySpec(key.getBytes("UTF-8"), KEY_ALGORITHM);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); //实例化Cipher对象,它用于完成实际的加密操作
cipher.init(Cipher.ENCRYPT_MODE, k); //初始化Cipher对象,设置为加密模式
return Base64.encode(cipher.doFinal(data.getBytes("UTF-8"))); //执行加密操作。加密后的结果用Base64编码进行传输
}
/** ral = 1 end **/
/**
* 加密 ral=2
* @param content
* 需要加密的内容
* @return
*/
public static String AESencrypt2(String content,String key) {
try {
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, genKey(key));// 初始化
byte[] result = cipher.doFinal(byteContent);
return parseByte2HexStr(result); // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @mock 根据密钥获得 SecretKeySpec
* @param strKey 加密解密密钥
* @return
*/
private static SecretKeySpec genKey(String strKey){
byte[] enCodeFormat = {0};
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
secureRandom.setSeed(strKey.getBytes());
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();
enCodeFormat = secretKey.getEncoded();
} catch (Exception e) {
e.printStackTrace();
}
return new SecretKeySpec(enCodeFormat, "AES");
}
/**
* 将二进制转换成16进制
* @param buf
* @return
*/
private static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/** ral = 2 end **/
/**
* MD5加密 生成32位md5码
*/
public static String AESencrypt3(String inStr,String key){
MessageDigest md5 = null;
try{
md5 = MessageDigest.getInstance("MD5");
}catch (Exception e){
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++){
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return (hexValue.toString()+key).toUpperCase();
}
/** ral = 3 end **/
/**
* base64加密 生成32位md5码
*/
public static String AESencrypt4(String content,String key){
byte[] bt = content.getBytes();
String str = (new BASE64Encoder()).encodeBuffer(bt);
return (str.trim()+key).toUpperCase();
}
/** ral = 4 end **/
/**
* Takes the raw bytes from the digest and formats them correct.
*
* @param bytes the raw bytes from the digest.
* @return the formatted bytes.
*/
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString().toUpperCase();
}
public static String AESencrypt5(String content,String key) {
if (content == null) {
return null;
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(content.getBytes());
return (getFormattedText(messageDigest.digest())+key);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** ral = 5 end **/
/**
* 利用java原生的摘要实现SHA256加密
* @param str 加密后的报文
* @return
*/
public static String AESencrypt6(String content,String key){
MessageDigest messageDigest;
String encodeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(content.getBytes("UTF-8"));
encodeStr = byte2Hex(messageDigest.digest());
} catch (Exception e) {
e.printStackTrace();
}
return (encodeStr+key).toUpperCase();
}
/**
* 将byte转为16进制
* @param bytes
* @return
*/
private static String byte2Hex(byte[] bytes){
StringBuffer stringBuffer = new StringBuffer();
String temp = null;
for (int i=0;i<bytes.length;i++){
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length()==1){
//1得到一位的进行补0操作
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
/** ral = 6 end **/
/*数据加密开始*/
public static String GetAES(String value,int rand) throws Exception{
/*返回数据:加密数据+#+密钥*/
String key_vue = "";
/*密钥*/
String km = "";
GetKey key = new GetKey();
switch (rand){
case 1:
km = key.KeyValue16();
key_vue = ToMD5.MD5(AESencrypt1(value,km))+"#"+km;
break;
case 2:
km = key.KeyValue32();
key_vue = ToMD5.MD5(AESencrypt2(value,km))+"#"+km;
break;
case 3:
km = key.KeyValue32();
key_vue = ToMD5.MD5(AESencrypt3(value,km))+"#"+km;
break;
case 4:
km = key.KeyValue32();
key_vue = ToMD5.MD5(AESencrypt4(value,km))+"#"+km;
break;
case 5:
km = key.KeyValue32();
key_vue = ToMD5.MD5(AESencrypt5(value,km))+"#"+km;
break;
case 6:
km = key.KeyValue32();
key_vue = ToMD5.MD5(AESencrypt6(value,km))+"#"+km;
break;
default:
km = key.KeyValue32();
key_vue = ToMD5.MD5("JIAMISHUJUCUOWU")+"#"+km;
break;
}
return key_vue;
}
/*数据加密开始,加密数据,算法,密钥*/
public static String GetAESEnd(String value,int rand,String km) throws Exception{
/*返回数据:加密数据*/
String key_vue = "";
switch (rand){
case 1:
key_vue = ToMD5.MD5(AESencrypt1(value,km));
break;
case 2:
key_vue = ToMD5.MD5(AESencrypt2(value,km));
break;
case 3:
key_vue = ToMD5.MD5(AESencrypt3(value,km));
break;
case 4:
key_vue = ToMD5.MD5(AESencrypt4(value,km));
break;
case 5:
key_vue = ToMD5.MD5(AESencrypt5(value,km));
case 6:
key_vue = ToMD5.MD5(AESencrypt6(value,km));
break;
default:
key_vue = ToMD5.MD5("JIAMISHUJUCUOWU");
break;
}
return key_vue;
}
}
转MD5:
package com.auth.sp.common.utils;
import java.security.MessageDigest;
/**
* 作者: 薛俊鹏
* 时间:2018/10/15 on 17:19 .
* 描述:MD5算法
* 内容:
* 状态: 编写/修改
*/
public class ToMD5 {
public static String MD5(String key) {
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
try {
byte[] btInput = key.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
}
登录方法:
package com.auth.sp.common.controller;
import com.auth.sp.common.aspect.ClearData;
import com.auth.sp.common.entity.LoginSystyem;
import com.auth.sp.common.entity.PwdKey;
import com.auth.sp.common.entity.SysKey;
import com.auth.sp.common.entity.SysUser;
import com.auth.sp.common.service.SysKeyService;
import com.auth.sp.common.service.SysUserService;
import com.auth.sp.common.shiro.ErrorReason;
import com.auth.sp.common.shiro.Token;
import com.auth.sp.common.utils.IPUtils;
import com.auth.sp.common.utils.Ognl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
/**
* 作者: 薛俊鹏
* 时间:2018/10/12 on 17:55 .
* 描述:登陆方法及控制 数据的拦截在权限机中处理 所有不合法的请求重置到登陆页面
* 内容:
* 状态: 编写/修改
*/
@RestController
public class LoginController {
Log log = LogFactory.getLog(LoginController.class);
@Autowired
private SysUserService userService;
@Autowired
private SysKeyService keyService;
/**登陆测试**/
@RequestMapping(value = "log_in",method = RequestMethod.GET)
public String Login(){
List<SysUser> list = userService.SelectUser();
SysUser user = new SysUser();
for (int i = 0; i < list.size(); i++) {
user = list.get(i);
System.out.println("账户:"+user.getAccount());
}
return "OK-Account";
}
/**登录进入系统 全部返回json 数据**/
@RequestMapping(value = "loginUser",method = RequestMethod.POST)
public String LoginUser(@ModelAttribute LoginSystyem user, ModelMap model, HttpServletRequest request, HttpServletResponse response)
throws Exception{
/**用户信息判断**/
if(Ognl.isEmpty(user) || Ognl.isEmpty(user.getAccount()) || Ognl.isEmpty(user.getPwd())){
/**清空对象**/
user = null;
/**清空缓存数据**/
response = ClearData.Clear(request,response);
return ErrorReason.getErrorInfo(1).getErrorInfo();/*账户信息不能为空,请重新输入!*/
}else{
/**判断账户信息的准确性**/
SysUser u = userService.selectByAccount(user.getAccount());
/**用户不存在**/
if(Ognl.isEmpty(u)){
/**清空对象**/
user = null;
u = null;
/**清空缓存数据**/
response = ClearData.Clear(request,response);
return ErrorReason.getErrorInfo(2).getErrorInfo();/*该账户信息不存在!*/
}else{
/**存在用户 记录登录IP**/
u.setLogin_ip(IPUtils.getLocalIP());
userService.updateByPrimaryKeySelective(u);
/**根据用户id查询用户的密钥信息**/
SysKey sysKey = keyService.selectByUserId(u.getId());
if(Ognl.isEmpty(sysKey)){
log.info("sysKey数据异常,请及时处理!");
/**清空对象**/
user = null;
sysKey = null;
/**清空缓存数据**/
response = ClearData.Clear(request,response);
return ErrorReason.getErrorInfo(3).getErrorInfo();/*账户异常,请及时联系管理员!*/
}else{
/**密码输入超过5次,踢出系统,清除登陆痕迹**/
if(u.getError_time()>=5){
/**清空对象**/
user = null;
user = null;
sysKey = null;
/**清空缓存数据**/
response = ClearData.Clear(request,response);
return "密码多次输入错误,"+ErrorReason.getErrorInfo(6).getErrorInfo();
}else {
/**数据置换,防止SQL攻击**/
PwdKey pwdKey = new PwdKey();
pwdKey.setKey(sysKey.getUser_key());
pwdKey.setValue(sysKey.getPwd());
pwdKey.setAccount(user.getPwd());
pwdKey.setNum(u.getAlg());
boolean isOk = SysUserController.IsPassPwd(pwdKey);
/**密码一致确认身份信息,密码不一致,踢出系统**/
if (!isOk) {
log.info(user.getAccount() + "密码输入错误!");
/**密码错误更新错误密码次数**/
u.setError_time(u.getError_time() + 1);
/**错误次数达到上限,冻结用户**/
if (u.getError_time() >= 5) {
u.setFreeze(0);
u.setReason("密码输入错误次数超过5次");
}
userService.updateByPrimaryKeySelective(u);
/**清空对象**/
user = null;
pwdKey = null;
user = null;
sysKey = null;
/**清空缓存数据**/
response = ClearData.Clear(request, response);
return ErrorReason.getErrorInfo(4).getErrorInfo();/*密码输入错误*/
} else {
if(u.getFreeze()==0){
/**清空对象**/
user = null;
u = null;
pwdKey = null;
sysKey = null;
/**清空缓存数据**/
response = ClearData.Clear(request, response);
return ErrorReason.getErrorInfo(6).getErrorInfo()+"请联系管理员处理!";
}else {
/**更新用户信息**/
u.setError_time(0);
u.setReason("");
userService.updateByPrimaryKeySelective(u);
log.info(u.getAccount() + "欢迎进入系统...");
/**进入系统之后,全称使用加密的身份验证,验证失败,或者超时,踢出系统**/
// request.getSession().setAttribute("token", Token.EncryMacSHA(u.getAccount()));
request.getSession().setAttribute("uname1",u.getAccount());
HttpSession session = request.getSession();
request.getSession().setAttribute("u",u);
session.setAttribute("token",Token.EncryMacSHA(u.getAccount()));
session.setAttribute("uname",u.getAccount());
pwdKey = null;
user = null;
sysKey = null;
String result = ErrorReason.getErrorInfo(5).getErrorCode();/*授权通过*/
return result;
}
}
}
}
}
}
}
}
数据清除:
package com.auth.sp.common.aspect;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
/**
* 作者: 薛俊鹏
* 时间:2018/10/22 on 10:53 .
* 描述:主要用于数据的清空和初始化处理
* 内容:
* 状态: 编写/修改
*/
public class ClearData {
/**session的初始化和清空操作**/
public static void initSession(HttpServletRequest request){
/**获取所有session 枚举**/
Enumeration em = request.getSession().getAttributeNames();
while(em.hasMoreElements()){
request.getSession().removeAttribute(em.nextElement().toString());
}
}
/**清空cookie**/
public static HttpServletResponse CleanCookies(HttpServletRequest request,HttpServletResponse response){
/**获取所有cookie信息**/
Cookie[] cookies=request.getCookies();
for(Cookie cookie: cookies){
/**使用完立即删除**/
cookie.setMaxAge(0);
/**所有路径下的cookie**/
cookie.setPath("/");
response.addCookie(cookie);
}
return response;
}
public static HttpServletResponse Clear(HttpServletRequest request,HttpServletResponse response){
/**清空session**/
ClearData.initSession(request);
request.getSession().invalidate();
/**清空cookie**/
response = ClearData.CleanCookies(request,response);
return response;
}
}
错误信息封装:
package com.auth.sp.common.shiro;
/**
* 作者: 薛俊鹏
* 时间:2018/10/25 on 11:42 .
* 描述:错误定义
* 内容:
* 状态: 编写/修改
*/
public class ErrorBean {
/**错误标识**/
private int identification;
/**错误代码**/
private String errorCode;
/**错误中文**/
private String errorInfo;
/**错误英文**/
private String errorMsg;
// get set
public int getIdentification() {
return identification;
}
public void setIdentification(int identification) {
this.identification = identification;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorInfo() {
return errorInfo;
}
public void setErrorInfo(String errorInfo) {
this.errorInfo = errorInfo;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
错误信息配置:
package com.auth.sp.common.shiro;
/**
* 作者: 薛俊鹏
* 时间:2018/10/25 on 11:41 .
* 描述:定义错误信息
* 内容:
* 状态: 编写/修改
*/
public class ErrorReason {
public static ErrorBean getErrorInfo(int identification) {
String code = "9999";/*错误代码*/
String info = "未知错误";/*中文信息*/
String errorMsg = "unknown error";/*英文解释*/
switch (identification) {
case 1:
code = "N0001";
info = "账户信息不能为空,请重新输入!";
errorMsg = "Account information can not be empty. Please re-enter it!";
break;
case 2:
code = "N0002";
info = "该账户信息不存在!";
errorMsg = "The account information does not exist!";
break;
case 3:
code = "N0003";
info = "账户异常,请及时联系管理员!";
errorMsg = "Account exception, please contact the administrator in time!";
break;
case 4:
code = "N0004";
info = "密码输入错误,请重新输入!";
errorMsg = "Password input error, please re input!";
break;
case 5:
code = "N0005";
info = "授权通过!";
errorMsg = "Permit passage!";
break;
case 6:
code = "N0006";
info = "账户已被系统冻结!";
errorMsg = "The account has been frozen!";
break;
default:
code = "N9999";
info = "未知异常,请联系管理员!";
errorMsg = "Unknown exception, please contact the administrator!";
break;
}
ErrorBean errorInfo = new ErrorBean();
errorInfo.setErrorCode(code);
errorInfo.setErrorInfo(info);
errorInfo.setErrorMsg(errorMsg);
return errorInfo;
}
}