package cn.com.qmth.mps.service.impl; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.qmth.boot.core.exception.StatusException; import com.qmth.boot.core.security.annotation.AuthorizationComponent; import com.qmth.boot.core.security.service.AuthorizationService; import com.qmth.boot.tools.signature.SignatureType; import com.qmth.boot.tools.uuid.FastUUID; import cn.com.qmth.mps.bean.User; import cn.com.qmth.mps.config.SysProperty; import cn.com.qmth.mps.entity.UserEntity; import cn.com.qmth.mps.entity.WxappAccessTokenEntity; import cn.com.qmth.mps.entity.WxappInfoEntity; import cn.com.qmth.mps.enums.Role; import cn.com.qmth.mps.exception.ParameterExceptions; import cn.com.qmth.mps.service.AuthService; import cn.com.qmth.mps.service.SessionService; import cn.com.qmth.mps.service.UserService; import cn.com.qmth.mps.service.WxappAccessTokenService; import cn.com.qmth.mps.service.WxappInfoService; import cn.com.qmth.mps.util.ByteUtil; import cn.com.qmth.mps.util.HttpUtil; import cn.com.qmth.mps.util.SHA256; import cn.com.qmth.mps.vo.AdminLoginVo; import net.sf.json.JSONObject; import sun.misc.BASE64Decoder; @AuthorizationComponent @Service public class AuthServiceImpl implements AuthorizationService, AuthService { @Autowired private UserService userService; @Autowired private SessionService sessionService; @Autowired private WxappAccessTokenService wxappAccessTokenService; @Autowired private SysProperty sysProperty; @Autowired private WxappInfoService wxappInfoService; @Override public AdminLoginVo loginWxAppCode(String loginCode) { JSONObject auth=getAuthorization(loginCode); String openid=auth.getString("openid"); WxappInfoEntity wi=wxappInfoService.getByOpenId(openid); if(wi==null) { throw ParameterExceptions.OPENID_NOT_FOUND; } UserEntity userEntity = userService.getByLoginName(wi.getPhone()); if (userEntity == null) { throw new StatusException("微信所绑定手机号系统中不存在"); } if (!userEntity.getEnable()) { throw new StatusException("该用户已禁用"); } if (!userEntity.getRoleId().equals(Role.SECTION_LEADER.getId())) { throw new StatusException("该用户不是科组长"); } User user = new User(); user.setName(userEntity.getName()); user.setSchoolId(userEntity.getSchoolId()); user.setId(userEntity.getId()); user.setRole(Role.getById(userEntity.getRoleId())); user.setAccessToken(FastUUID.get()); user.buildKey(); sessionService.userLogin(user); AdminLoginVo vo = new AdminLoginVo(); vo.setAccessToken(user.getAccessToken()); vo.setName(user.getName()); vo.setSessionId(user.getSessionId()); vo.setSchoolId(user.getSchoolId()); vo.setRole(user.getRole()); return vo; } @Override public AdminLoginVo loginAdmin(String loginName, String password) { UserEntity userEntity = userService.getByLoginName(loginName); if (userEntity == null) { throw new StatusException("账号不存在"); } if (!userEntity.getEnable()) { throw new StatusException("该用户已禁用"); } if (userEntity.getRoleId().equals(Role.SECTION_LEADER.getId())) { throw new StatusException("科组长无权限登录"); } byte[] bytes = SHA256.encode(password); String encodePassword = ByteUtil.toHexAscii(bytes); if (!encodePassword.equals(userEntity.getPassword())) { throw new StatusException("密码错误"); } User user = new User(); user.setName(userEntity.getName()); user.setSchoolId(userEntity.getSchoolId()); user.setId(userEntity.getId()); user.setRole(Role.getById(userEntity.getRoleId())); user.setAccessToken(FastUUID.get()); user.buildKey(); sessionService.userLogin(user); AdminLoginVo vo = new AdminLoginVo(); vo.setAccessToken(user.getAccessToken()); vo.setName(user.getName()); vo.setSessionId(user.getSessionId()); vo.setSchoolId(user.getSchoolId()); vo.setRole(user.getRole()); return vo; } @Override public void logout(User user) { sessionService.userLogout(user); } @Override public User findByIdentity(String identity, SignatureType type, String path) { User user = sessionService.getSessionUser(identity); return user; } @Override public boolean hasPermission(User user, String path) { sessionService.updateUserSession(user); return true; } @Override public void modifyWxappAccessToken() { WxappAccessTokenEntity token = wxappAccessTokenService.getWxappAccessToken(); long now = System.currentTimeMillis(); if (StringUtils.isEmpty(token.getAccessToken()) || token.getExpiresTime() - now <= 15 * 60 * 1000) { Map params = new HashMap<>(); params.put("appid", sysProperty.getWxappAppid()); params.put("secret", sysProperty.getWxappSecret()); params.put("grant_type", "client_credential"); String ret; try { ret = HttpUtil.httpActionGet("https://api.weixin.qq.com/cgi-bin/token", null, params); } catch (Exception e) { throw new StatusException("获取失败", e); } JSONObject jo = JSONObject.fromObject(ret); if (jo.containsKey("errcode")) { throw new StatusException("获取失败," + jo.getString("errmsg")); } int ex = jo.getInt("expires_in"); String at = jo.getString("access_token"); token.setAccessToken(at); token.setExpiresTime(now + ex * 1000); wxappAccessTokenService.updateById(token); } } @Transactional @Override public AdminLoginVo loginWxAppByEncryptedData(String loginCode, String encryptedData, String iv) { JSONObject auth=getAuthorization(loginCode); String openid=auth.getString("openid"); JSONObject jo=decrypt(encryptedData, iv, auth.getString("session_key")); String phone=jo.getString("purePhoneNumber"); UserEntity userEntity = userService.getByLoginName(phone); if (userEntity == null) { throw new StatusException("微信所绑定手机号系统中不存在"); } if (!userEntity.getEnable()) { throw new StatusException("该用户已禁用"); } if (!userEntity.getRoleId().equals(Role.SECTION_LEADER.getId())) { throw new StatusException("该用户不是科组长"); } WxappInfoEntity wi=wxappInfoService.getByOpenId(openid); if(wi==null) { wi=new WxappInfoEntity(); wi.setOpenid(openid); } wi.setPhone(phone); wxappInfoService.saveOrUpdate(wi); User user = new User(); user.setName(userEntity.getName()); user.setSchoolId(userEntity.getSchoolId()); user.setId(userEntity.getId()); user.setRole(Role.getById(userEntity.getRoleId())); user.setAccessToken(FastUUID.get()); user.buildKey(); sessionService.userLogin(user); AdminLoginVo vo = new AdminLoginVo(); vo.setAccessToken(user.getAccessToken()); vo.setName(user.getName()); vo.setSessionId(user.getSessionId()); vo.setSchoolId(user.getSchoolId()); vo.setRole(user.getRole()); return vo; } private JSONObject getAuthorization(String loginCode) { Map params = new HashMap<>(); params.put("appid", sysProperty.getWxappAppid()); params.put("secret", sysProperty.getWxappSecret()); params.put("js_code", loginCode); params.put("grant_type", "authorization_code"); String ret; try { ret = HttpUtil.httpActionGet("https://api.weixin.qq.com/sns/jscode2session", null, params); } catch (Exception e) { throw new StatusException("登录失败", e); } JSONObject jo = JSONObject.fromObject(ret); if (jo.containsKey("errcode")) { throw new StatusException("登录失败," + jo.getString("errmsg")); } return jo; } private JSONObject decrypt(String encryptedData, String iv, String sessionKey){ String cipherString = "AES/CBC/PKCS5Padding"; String jsonStr; try { BASE64Decoder base64Decoder = new BASE64Decoder(); /** * 小程序加密数据解密算法 * https://developers.weixin.qq.com/miniprogram/dev/api/signature.html#wxchecksessionobject * 1.对称解密的目标密文为 Base64_Decode(encryptedData)。 2.对称解密秘钥 aeskey = * Base64_Decode(session_key), aeskey 是16字节。 3.对称解密算法初始向量 * 为Base64_Decode(iv),其中iv由数据接口返回。 */ byte[] encryptedByte = base64Decoder.decodeBuffer(encryptedData); byte[] sessionKeyByte = base64Decoder.decodeBuffer(sessionKey); byte[] ivByte = base64Decoder.decodeBuffer(iv); /** * 以下为AES-128-CBC解密算法 */ SecretKeySpec skeySpec = new SecretKeySpec(sessionKeyByte, "AES"); Cipher cipher = Cipher.getInstance(cipherString); IvParameterSpec ivParameterSpec = new IvParameterSpec(ivByte); cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec); byte[] original = cipher.doFinal(encryptedByte); jsonStr = new String(original); } catch (Exception e) { throw new StatusException("登录失败,信息有误 ",e); } JSONObject jsonObject = JSONObject.fromObject(jsonStr); return jsonObject; } @Transactional @Override public AdminLoginVo loginWxAppByPhoneCode(String loginCode,String phoneCode) { Map params = new HashMap<>(); params.put("code", phoneCode); String ret; try { ret = HttpUtil.httpActionPost("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + wxappAccessTokenService.getWxappAccessToken().getAccessToken(), null, params); } catch (Exception e) { throw new StatusException("登录失败", e); } JSONObject jo = JSONObject.fromObject(ret); if (jo.getInt("errcode") != 0) { throw new StatusException("登录失败," + jo.getString("errmsg")); } String phone=jo.getJSONObject("phone_info").getString("purePhoneNumber"); UserEntity userEntity = userService.getByLoginName(phone); if (userEntity == null) { throw new StatusException("微信所绑定手机号系统中不存在"); } if (!userEntity.getEnable()) { throw new StatusException("该用户已禁用"); } if (!userEntity.getRoleId().equals(Role.SECTION_LEADER.getId())) { throw new StatusException("该用户不是科组长"); } JSONObject auth=getAuthorization(loginCode); String openid=auth.getString("openid"); WxappInfoEntity wi=wxappInfoService.getByOpenId(openid); if(wi==null) { wi=new WxappInfoEntity(); wi.setOpenid(openid); } wi.setPhone(phone); wxappInfoService.saveOrUpdate(wi); User user = new User(); user.setName(userEntity.getName()); user.setSchoolId(userEntity.getSchoolId()); user.setId(userEntity.getId()); user.setRole(Role.getById(userEntity.getRoleId())); user.setAccessToken(FastUUID.get()); user.buildKey(); sessionService.userLogin(user); AdminLoginVo vo = new AdminLoginVo(); vo.setAccessToken(user.getAccessToken()); vo.setName(user.getName()); vo.setSessionId(user.getSessionId()); vo.setSchoolId(user.getSchoolId()); vo.setRole(user.getRole()); return vo; } }