package com.vci.ubcs.code.service.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.vci.ubcs.code.entity.TokenUserObject;
|
import com.vci.ubcs.code.service.IPasswordFreeLoginService;
|
import com.vci.ubcs.starter.util.HttpUtils;
|
import com.vci.ubcs.system.cache.NacosConfigCache;
|
import io.jsonwebtoken.Claims;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.http.auth.AuthenticationException;
|
import org.springblade.core.jwt.JwtUtil;
|
import org.springblade.core.jwt.props.JwtProperties;
|
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.redis.cache.BladeRedis;
|
import org.springblade.core.secure.BladeUser;
|
import org.springblade.core.tool.support.Kv;
|
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.ObjectUtil;
|
import org.springblade.core.tool.utils.SpringUtil;
|
import org.springblade.core.tool.utils.StringUtil;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.MediaType;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
|
import javax.servlet.ServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.logging.Logger;
|
|
import static com.vci.ubcs.starter.util.AESUtils.aesDecrypt;
|
import static com.vci.ubcs.starter.util.AESUtils.aesEncrypt;
|
import static org.springblade.core.secure.utils.AuthUtil.parseJWT;
|
|
/**
|
* 免密登录服务
|
* @author ludc
|
* @date 2023/9/11 15:45
|
*/
|
@Service
|
@Slf4j
|
public class PasswordFreeLoginServiceImpl implements IPasswordFreeLoginService {
|
|
// 通过服务注册中心获取网关的端口号
|
@Autowired
|
private DiscoveryClient discoveryClient;
|
|
// 配置的免密登录的账号所属的租户id
|
@Value("${password-free.pwd-free-tenant-id:000000}")
|
private String pwdFreeTenantId;
|
|
// 配置的token在redis中的生存时间
|
@Value("${password-free.token-redis-expire:36000}")
|
private Long tokenRedisExpire;
|
|
@Value("${password-free.pwd-free-addr:localhost}")
|
private String pwdFreeAddr;
|
|
@Value("${password-free.client-id:a104c4fd2f0e4958}")
|
private String clientId;//应用ID
|
|
@Value("${password-free.secret-key:9fbd170bd83eb869}")
|
private String secretKey;//应用秘钥
|
|
@Autowired
|
private BladeRedis bladeRedis;
|
|
// 缓存名
|
public static final String PWD_FREE_LOGIN_TOKEN = "pwdFreeLogin:Token:";
|
private static JwtProperties jwtProperties;
|
|
/**
|
* 根据服务名获取端口号
|
* @param serviceId
|
* @return
|
*/
|
public String getGatewayPort(String serviceId) {
|
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
|
if (!instances.isEmpty()) {
|
ServiceInstance gatewayInstance = instances.get(0);
|
return String.valueOf(gatewayInstance.getPort());
|
}
|
return "8080";
|
}
|
|
/**
|
* 免密登录,改变当前webservice请求的header
|
* @param userName 账号
|
* @param servletRequest
|
* @return boolean
|
* @throws AuthenticationException
|
*/
|
@Override
|
public boolean pwdFreeLoginByBoolean(String userName, ServletRequest servletRequest) throws AuthenticationException {
|
//进来先判断缓存中是否存在token
|
// 请求来自己哪个ip地址
|
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
String ipAddr = request.getRemoteAddr();
|
// 先尝试从缓存当中取,存在就直接从缓存中获取
|
String authToken = bladeRedis.get(PWD_FREE_LOGIN_TOKEN+ipAddr+":"+userName);
|
// 解析token存放进attr中
|
String token2 = JwtUtil.getToken(authToken);
|
BladeUser user = this.getUser(token2);
|
//不存在就请求
|
if(Func.isEmpty(authToken) || Func.isEmpty(user) || !user.getTenantId().equals(NacosConfigCache.getAdminUserInfo().getTenantId())){
|
String responseBody = this.passwordFreeLogin(userName);
|
//拿到响应体其中包含token,用request中的ip地址作为键值,将token存入缓存
|
TokenUserObject tokenUserObject = null;
|
try {
|
tokenUserObject = JSON.parseObject(responseBody, TokenUserObject.class);
|
}catch (Exception e){
|
throw new ServiceException("鉴权响应内容转换为TokenUserObject失败:"+e.getMessage());
|
}
|
// 拼接token格式
|
authToken = "bearer " + tokenUserObject.getAccess_token();
|
// 将token存入缓存当中,过期时间为24小时
|
bladeRedis.setEx(PWD_FREE_LOGIN_TOKEN+ipAddr+":"+userName,"bearer "+tokenUserObject.getAccess_token(),tokenRedisExpire);
|
token2 = JwtUtil.getToken(authToken);
|
user = this.getUser(token2);
|
}
|
//request.setAttribute("Blade-Auth",token);
|
request.setAttribute("_BLADE_USER_REQUEST_ATTR_",user);
|
return true;
|
}
|
|
/**
|
* 免密登录请求发送
|
* @param userName 账号
|
* @return 返回token
|
* @throws AuthenticationException
|
*/
|
@Override
|
public String passwordFreeLogin(String userName) throws AuthenticationException {
|
// 免密登录接口地址
|
String loginUrl = "http://"+pwdFreeAddr+":"+this.getGatewayPort("ubcs-gateway")+"/ubcs-auth/oauth/token";
|
log.debug("当前免密登录调用地址:"+loginUrl);
|
// 请求ubcs-auth服务获取token,先设置请求头
|
HttpHeaders headers = new HttpHeaders();
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
headers.set("Authorization", "Basic c3dvcmQ6c3dvcmRfc2VjcmV0");
|
headers.set("Tenant-Id", pwdFreeTenantId);
|
//设置请求体参数
|
MultiValueMap<String,String> parameters = new LinkedMultiValueMap<String,String>();
|
parameters.add("username",userName);
|
parameters.add("grant_type", "passwordfree");
|
parameters.add("scope", "all");
|
parameters.add("type", "account");
|
String responseBody = null;
|
try {
|
// 发送POST请求
|
responseBody = HttpUtils.post(loginUrl, parameters,headers);
|
}catch (Exception e){
|
throw new AuthenticationException("调用鉴权服务ubcs-auth失败,原因:"+e.getMessage());
|
}
|
return responseBody;
|
}
|
|
/**
|
* 单点登录
|
* @param empCode
|
* @return
|
* @throws Exception
|
*/
|
@Override
|
public String ssoFreeLogin(String empCode) throws Exception {
|
if(Func.isBlank(empCode)){
|
throw new ServiceException("未获取到empCode参数");
|
}
|
String enStr2;
|
try {
|
String enStr1 = aesDecrypt(empCode, secretKey);
|
enStr2 = aesDecrypt(enStr1, clientId);
|
}catch (Exception e){
|
throw new ServiceException("empCode参数解密失败!原因:"+e.getMessage());
|
}
|
// 解密
|
log.debug("单点登录参数解密后:"+enStr2);
|
String token = this.passwordFreeLogin(enStr2);
|
return token;
|
}
|
|
/**
|
* 根据token获取用户信息
|
* @param token
|
* @return
|
*/
|
private static BladeUser getUser(String token) {
|
Claims claims = getClaims(token);
|
if (claims == null) {
|
return null;
|
} else {
|
String clientId = Func.toStr(claims.get("client_id"));
|
Long userId = Func.toLong(claims.get("user_id"));
|
String tenantId = Func.toStr(claims.get("tenant_id"));
|
String oauthId = Func.toStr(claims.get("oauth_id"));
|
String deptId = Func.toStrWithEmpty(claims.get("dept_id"), "-1");
|
String postId = Func.toStrWithEmpty(claims.get("post_id"), "-1");
|
String roleId = Func.toStrWithEmpty(claims.get("role_id"), "-1");
|
String account = Func.toStr(claims.get("account"));
|
String roleName = Func.toStr(claims.get("role_name"));
|
String userName = Func.toStr(claims.get("user_name"));
|
String nickName = Func.toStr(claims.get("nick_name"));
|
String tenantName = Func.toStr(claims.get("tenantName"));
|
String email = Func.toStr(claims.get("email"));
|
String deptName = Func.toStr(claims.get("deptName"));
|
String secretGrade = Func.toStr(claims.get("secretGrade"));
|
Kv detail = Kv.create().setAll((Map)claims.get("detail"));
|
BladeUser bladeUser = new BladeUser();
|
bladeUser.setClientId(clientId);
|
bladeUser.setUserId(userId);
|
bladeUser.setTenantId(tenantId);
|
bladeUser.setOauthId(oauthId);
|
bladeUser.setAccount(account);
|
bladeUser.setDeptId(deptId);
|
bladeUser.setPostId(postId);
|
bladeUser.setRoleId(roleId);
|
bladeUser.setRoleName(roleName);
|
bladeUser.setUserName(userName);
|
bladeUser.setNickName(nickName);
|
detail.put("tenantName", tenantName);
|
detail.put("deptName", deptName);
|
detail.put("email", email);
|
detail.put("secretGrade", secretGrade);
|
bladeUser.setDetail(detail);
|
return bladeUser;
|
}
|
}
|
|
/**
|
* 解析token
|
* @param authToken
|
* @return
|
*/
|
private static Claims getClaims(String authToken) {
|
Claims claims = null;
|
String token = null;
|
String tenantId;
|
if (StringUtil.isNotBlank(authToken)) {
|
token = JwtUtil.getToken(authToken);
|
}
|
if (StringUtil.isNotBlank(token)) {
|
claims = parseJWT(token);
|
}
|
if (ObjectUtil.isNotEmpty(claims) && getJwtProperties().getState()) {
|
tenantId = Func.toStr(claims.get("tenant_id"));
|
String userId = Func.toStr(claims.get("user_id"));
|
String accessToken = JwtUtil.getAccessToken(tenantId, userId, token);
|
if (!token.equalsIgnoreCase(accessToken)) {
|
return null;
|
}
|
}
|
|
return claims;
|
}
|
|
private static JwtProperties getJwtProperties() {
|
if (jwtProperties == null) {
|
jwtProperties = (JwtProperties) SpringUtil.getBean(JwtProperties.class);
|
}
|
|
return jwtProperties;
|
}
|
|
}
|