&为了提高用户的安全性,明文传递有很大可能造成用户资料泄露,利用RSA和AES来进行前端加密和后端解密
RSA原理可以自行百度。
UTF-8
UTF-8
1.8
2.11.0
2.3.0
org.springframework.boot
spring-boot-starter-web
javax.servlet
javax.servlet-api
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-websocket
org.springframework.boot
spring-boot-starter-aop
org.thymeleaf
thymeleaf
3.0.11.RELEASE
org.thymeleaf
thymeleaf-spring5
3.0.11.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
net.sourceforge.nekohtml
nekohtml
1.9.22
com.baomidou
mybatisplus-spring-boot-starter
1.0.5
com.baomidou
mybatis-plus
2.3
com.alibaba
druid-spring-boot-starter
1.1.9
mysql
mysql-connector-java
6.0.6
com.oracle
ojdbc6
11.2.0.3
org.apache.velocity
velocity-engine-core
2.0
org.apache.velocity
velocity-engine-core
2.0
com.alibaba
fastjson
1.2.47
org.apache.directory.studio
org.apache.commons.codec
1.8
org.springframework.boot
spring-boot-starter-log4j
1.3.8.RELEASE
org.slf4j
slf4j-log4j12
1.7.25
org.scala-lang
scala-library
${scala.version}
org.apache.spark
spark-core_2.11
${spark.version}
org.slf4j
slf4j-log4j12
log4j
log4j
org.apache.spark
spark-launcher_2.11
${spark.version}
org.apache.spark
spark-mllib_2.11
${spark.version}
org.apache.spark
spark-streaming_2.11
${spark.version}
org.projectlombok
lombok
1.16.22
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-jta-atomikos
org.apache.shiro
shiro-spring
1.3.2
org.springframework.boot
spring-boot-maven-plugin
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
/** */
/**
*
* RSA公钥/私钥/签名工具包
*
*
* 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
*
*
* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式
* 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,
* 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
*
*
* @author ANC 钟晓鸿
* @date 2019-10-30
*/
public class RSAUtils {
/** */
/**
* 加密算法RSA
*/
public static final String KEY_ALGORITHM = "RSA";
/** */
/**
* 签名算法
*/
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
/** */
/**
* 获取公钥的key
*/
private static final String PUBLIC_KEY = "RSAPublicKey";
/** */
/**
* 获取私钥的key
*/
private static final String PRIVATE_KEY = "RSAPrivateKey";
/** */
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/** */
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/** */
/**
* RSA 位数 如果采用2048 上面最大加密和最大解密则须填写: 245 256
*/
private static final int INITIALIZE_LENGTH = 1024;
/** */
/**
*
* 生成密钥对(公钥和私钥)
*
*
* @return
* @throws Exception
*/
public static Map genKeyPair() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(INITIALIZE_LENGTH);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/** */
/**
*
* 用私钥对信息生成数字签名
*
*
* @param data 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateK);
signature.update(data);
return Base64.encodeBase64String(signature.sign());
}
/** */
/**
*
* 校验数字签名
*
*
* @param data 已加密数据
* @param publicKey 公钥(BASE64编码)
* @param sign 数字签名
* @return
* @throws Exception
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK);
signature.update(data);
return signature.verify(Base64.decodeBase64(sign));
}
/** */
/**
*
* 私钥解密
*
*
* @param encryptedData 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/** */
/**
*
* 公钥解密
*
*
* @param encryptedData 已加密数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/** */
/**
*
* 公钥加密
*
*
* @param data 源数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/** */
/**
*
* 私钥加密
*
*
* @param data 源数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/** */
/**
*
* 获取私钥
*
*
* @param keyMap 密钥对
* @return
* @throws Exception
*/
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return Base64.encodeBase64String(key.getEncoded());
}
/** */
/**
*
* 获取公钥
*
*
* @param keyMap 密钥对
* @return
* @throws Exception
*/
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return Base64.encodeBase64String(key.getEncoded());
}
/**
* java端公钥加密
*/
public static String encryptedDataOnJava(String data, String PUBLICKEY) {
try {
data = Base64.encodeBase64String(encryptByPublicKey(data.getBytes(), PUBLICKEY));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return data;
}
/**
* java端私钥解密
*/
public static String decryptDataOnJava(String data, String PRIVATEKEY) {
String temp = "";
try {
byte[] rs = Base64.decodeBase64(data);
temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return temp;
}
public static void main(String[] args) throws Exception{
Map map = genKeyPair();
//获得私钥
System.out.println(getPrivateKey(map));
System.out.println("----------------------------------------------------------------");
//获得公钥
System.out.println(getPublicKey(map));
}
}
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* 前后端数据传输加密工具类
* @author ANC 钟晓鸿
* 2019/10/30
*/
public class AesEncryptUtils {
//参数分别代表 算法名称/加密模式/数据填充方式
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
/**
* 加密
* @param content 加密的字符串
* @param encryptKey key值
* @return
* @throws Exception
*/
public static String encrypt(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
byte[] b = cipher.doFinal(content.getBytes("utf-8"));
// 采用base64算法进行转码,避免出现中文乱码
return Base64.encodeBase64String(b);
}
/**
* 解密
* @param encryptStr 解密的字符串
* @param decryptKey 解密的key值
* @return
* @throws Exception
*/
public static String decrypt(String encryptStr, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
// 采用base64算法进行转码,避免出现中文乱码
byte[] encryptBytes = Base64.decodeBase64(encryptStr);
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
}
package com.dfdk.datamanage.config;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Map;
/**
* @author ANC 钟晓鸿
* @desc 请求数据解密
* @date 2019/10/30
*/
@ControllerAdvice(basePackages = "com.dfdk.datamanage.controller")
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);
@Value("${server.private.key}")
private String SERVER_PRIVATE_KEY;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
return true;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) throws IOException {
try {
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
//获取注解配置的包含和去除字段
SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
//入参是否需要解密
encode = serializedField.inDecode();
}
if (encode) {
logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
return new MyHttpInputMessage(inputMessage);
}else{
return inputMessage;
}
} catch (Exception e) {
e.printStackTrace();
logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:"+e.getMessage());
return inputMessage;
}
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
return body;
}
class MyHttpInputMessage implements HttpInputMessage {
private HttpHeaders headers;
private InputStream body;
public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
this.headers = inputMessage.getHeaders();
this.body = IOUtils.toInputStream(easpString(IOUtils.toString(inputMessage.getBody(),"utf-8")));
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
/**
*
* @param requestData
* @return
*/
public String easpString(String requestData) {
if(requestData != null && !requestData.equals("")){
Map map = new Gson().fromJson(requestData,new TypeToken
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* @author ANC 钟晓鸿
* @desc 返回数据加密
* @date 2019/10/30 20:17
*/
@ControllerAdvice(basePackages = "com.xxx.xxx.controller")
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);
@Value("${client.public.key}")
private String CLIENT_PUBLIC_KEY;
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
//获取注解配置的包含和去除字段
SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
//出参是否需要加密
encode = serializedField.outEncode();
}
if (encode) {
logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
ObjectMapper objectMapper = new ObjectMapper();
try {
String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
// 生成aes秘钥
String aseKey = getRandomString(16);
// rsa加密
String encrypted = RSAUtils.encryptedDataOnJava(aseKey, CLIENT_PUBLIC_KEY);
// aes加密
String requestData = AesEncryptUtils.encrypt(result, aseKey);
Map map = new HashMap<>();
map.put("encrypted", encrypted);
map.put("requestData", requestData);
return map;
} catch (Exception e) {
e.printStackTrace();
logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
}
}
return body;
}
/**
* 创建指定位数的随机字符串
* @param length 表示生成字符串的长度
* @return 字符串
*/
public static String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
/**
* @author ANC 钟晓鸿
* @desc 请求数据解密
* @date 2019/10/30
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecurityParameter {
/**
* 入参是否解密,默认解密
*/
boolean inDecode() default true;
/**
* 出参是否加密,默认加密
*/
boolean outEncode() default true;
}
RSA+AES 加解密
服务端公钥:
js可以去官网自行下载,接下来开始整合shiro
mport org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
/**
* @author ANC
* @date 2019/10/09 15:58
*/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
System.out.println("ShiroConfiguration.shiroFilter执行...");
ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
filterFactory.setSecurityManager(securityManager);
//拦截器
LinkedHashMap hashMap = new LinkedHashMap<>();
// 配置不会被拦截的链接 按顺序判断
hashMap.put("/static/**", "anon");
hashMap.put("/testEncrypt", "anon");
hashMap.put("/loginCheck","anon");
//配置退出 过滤器,其中的具体的退出代码shiro已经替我们实现了
hashMap.put("/logout", "logout");
//过滤链定义,从上向下顺序执行,一般将/**放在最为下边:这是一个坑呢,一不小心代码就不好使了;
//authc:所有url都必须认证通过才可以访问;
//anon:所有url都都可以匿名访问
hashMap.put("/**","authc");
filterFactory.setLoginUrl("/rsa");
filterFactory.setSuccessUrl("/index");
//未授权页面
filterFactory.setUnauthorizedUrl("/run/403");
filterFactory.setFilterChainDefinitionMap(hashMap);
return filterFactory;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroReaml());
return securityManager;
}
@Bean
public ShiroReaml shiroReaml() {
return new ShiroReaml();
}
}
import com.dfdk.datamanage.entity.SysUser;
import com.dfdk.datamanage.services.SysUserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**自定义Reaml域
* @author ANC
* @date 2019/10/09 9:25
*/
public class ShiroReaml extends AuthorizingRealm {
@Autowired
private SysUserService publicUserDao;
/**
* 授权
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println(" 授权方法执行..................");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUser sysUser = (SysUser)principals.getPrimaryPrincipal();
//遍历用户角色信息
/*for (SysRole role: sysUser.getRoleList()) {
authorizationInfo.addRole(role.getRole());
//获取用户权限信息
for (SysPermission permission:role.getPermissions()) {
authorizationInfo.addStringPermission(permission.getPermission());
}
}*/
return authorizationInfo;
}
/**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("MyShiroRealm.doGetAuthenticationInfo()认证执行.......");
//获取登录账户
String loginEmail = token.getPrincipal().toString();
//通过username从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
SysUser siweeEmail = publicUserDao.findBySwEmail(loginEmail);
if (siweeEmail == null) {
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
loginEmail,
siweeEmail.getPassword(),
getName()
);
System.out.println(".......认证执行成功.......");
return authenticationInfo;
}
}
package com.dfdk.datamanage.config.shiro;
import com.dfdk.datamanage.entity.SysUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
public class ShiroSessionManager {
/**
* 获取当前主体
* @return
*/
public static Subject getCurrentSubject() {
return SecurityUtils.getSubject();
}
/**
* 获取当前会话
* @return
*/
public static Session getSession() {
return getCurrentSubject().getSession();
}
/**
* 设置当前会话
* @param key
* @param value
*/
public static void setSession(Object key,Object value) {
getSession().setAttribute(key, value);
}
/**
* 根据key获取对应的值
* @param key
* @return
*/
public static Object getVal2Session(Object key) {
return getSession().getAttribute(key);
}
/**
* 获取当前用户
* @return
*/
public static SysUser getUser() {
return (SysUser) getCurrentSubject().getPrincipal();
}
/**
* 获取当前用户名
* @return
* @author Lanna
* @date 2018年7月30日
*/
public static String getUsername() {
return getUser().getUsername();
}
/**
* 获取当前用户ID
* @return
* @author Lanna
* @date 2018年7月30日
*/
public static String getUerId() {
return getUser().getUserid();
}
}
import com.dfdk.datamanage.entity.SysUser;
import com.dfdk.datamanage.util.Const;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
public class TokenManager {
/**
* 登录认证
* @param subject
* @param sysUser
*/
public static void login(Subject subject, SysUser sysUser) {
ByteSource salt = ByteSource.Util.bytes(Const.SALT_VALUE);
String MD5Pwd = new SimpleHash("MD5",sysUser.getPassword(),salt).toString();//MD5加密
UsernamePasswordToken token = new UsernamePasswordToken(sysUser.getUsername(), MD5Pwd);
subject.login(token);
}
}
首先发送请求登陆加密,然后后台解密,执行shiro认证过程
package com.dfdk.datamanage.controller;
import com.dfdk.datamanage.config.SecurityParameter;
import com.dfdk.datamanage.config.shiro.ShiroSessionManager;
import com.dfdk.datamanage.config.shiro.TokenManager;
import com.dfdk.datamanage.entity.SysRole;
import com.dfdk.datamanage.entity.SysUser;
import com.dfdk.datamanage.services.SysRoleService;
import com.dfdk.datamanage.services.SysUserService;
import com.dfdk.datamanage.util.Const;
import com.dfdk.datamanage.util.JsonResult;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Controller
@Scope(value = "prototype")
public class LoginController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
/**
*
* */
@RequestMapping("/loginCheck")
@ResponseBody
@SecurityParameter
public JsonResult login(@RequestBody SysUser sysUser, HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "rememberMe",defaultValue = "false") boolean isRemeber) {
SysUser model = sysUserService.findBySwEmail(sysUser.getUsername());
if(null == model){
return new JsonResult(new IncorrectCredentialsException("PWDERROR"));
}
Subject currentUser = ShiroSessionManager.getCurrentSubject();
if (!currentUser.isAuthenticated()) {//
try {
List roleList = sysRoleService.queryUserRoles(model.getUserid());
Map> roleMap = roleList.stream().collect(Collectors.groupingBy(SysRole::getStatus));
List roleUseList = roleMap.get("可用");
if(roleUseList==null) {
throw new NullPointerException("NOROLES");
}
TokenManager.login(currentUser, sysUser);
if (isRemeber == true) {
String value = sysUser.getUsername() + "##" + sysUser.getPassword();
//CookieUtil.setCookies(response, value);
} else {
//CookieUtil.delCookie(request,response,"logInfor");
}
return new JsonResult("SUCCESS");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
e = new IncorrectCredentialsException("PWDERROR");
return new JsonResult(e);
} catch (AuthenticationException e) {
e = new AuthenticationException("SERVERERROR");
return new JsonResult(e);
} catch (NullPointerException e) {
e = new NullPointerException("NOROLES");
return new JsonResult(e);
}
} else {
return new JsonResult("SUCCESS");
}
}
}
实体类这部分就不具体多写了,service业务层都是查询功能,以下是公钥和秘钥
server.private.key=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKVyo4YeawnUAJXJqIuoXUbU+u7r5Zs4SuwmP0ik+e5Gf5f1GhDWQBQ7zbn0oSwyq4/+9U6ygv1pZUSAj52RiQSS5oToJZMm9rb9GywMKNuAKbJ4ssgd619YvSQ7UGpFrfcEBFtnvfEyAq2WFePt58Q51xfNeKPhqNdNhB0z8WzzAgMBAAECgYBPlvlxYJqvbKwnYo5RONo+Y+CfJR4ccJUiSzfwU2TkKkfhKwiyBs9mrGpIRZVvNKTxrX4GsLtw+s27iXkNHODjapmNnq2OHdIawPY82NIeyZeeZ8Yzzu0oovh4kiTm3W7M30k1mXDDrCoZzoTtQcqC8zyzjYrLXSoDSdr/Re7sSQJBAODq38nQ7kTGuv/CvW6Q0XGRbblFU2ecUGtHL4CPHqwbF2kfD4c+Xh/YWP+U7ub7kmEjVBe1z43i/gJEO3QOSScCQQC8T9kNYfqUSDnfLftuvdt/xsnGYakw2S732GxQ9Jbk5+l4XmIUdqp5M8IMhbegLo28Fw7PZKVgqhUwNSE/q6VVAkAc/+uu19OA5qbBx1gpY1695+Rf2QJx/4OW8Wy8hLeNtUiFc03LQE1eicSf35IWEiXDhIyZKgYC41ug6y9HPXhNAkAWviH9rsafn/V1Uc1a+40F6pE151eSsbgtcLLsOA39SVD2G5gG1qoSB0E5V/DsZJLzk2lTfNlISmJStyfz05wdAkEAhaZiZprI0sOwND8hbVy4CNDSM+guDn2e53+rG3pyY6mT6clrA4nWulpko5sCMOcMRRZejU5PJY9S12kvAW8t6w==
client.public.key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClcqOGHmsJ1ACVyaiLqF1G1Pru6+WbOErsJj9IpPnuRn+X9RoQ1kAUO8259KEsMquP/vVOsoL9aWVEgI+dkYkEkuaE6CWTJva2/RssDCjbgCmyeLLIHetfWL0kO1BqRa33BARbZ73xMgKtlhXj7efEOdcXzXij4ajXTYQdM/Fs8wIDAQAB
到此就结束了,没有绝对安全的加密,只有相对安全,可以在此基础上多加一些安全措施