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.code.util.HttpUtils; import io.jsonwebtoken.Claims; 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 static org.springblade.core.secure.utils.AuthUtil.parseJWT; /** * 免密登录服务 * @author ludc * @date 2023/9/11 15:45 */ @Service public class PasswordFreeLoginServiceImpl implements IPasswordFreeLoginService { // 通过服务注册中心获取网关的端口号 @Autowired private DiscoveryClient discoveryClient; // 配置的免密登录的账号所属的租户id @Value("${password-free.pwd-free-tenant-id}") // 配置的token在redis中的生存时间 private String pwdFreeTenantId; @Value("${password-free.token-redis-expire}") private Long tokenRedisExpire; @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 instances = discoveryClient.getInstances(serviceId); if (!instances.isEmpty()) { ServiceInstance gatewayInstance = instances.get(0); return String.valueOf(gatewayInstance.getPort()); } return "8080"; } /** * 免密登录,改变当前webservice请求的header * @param userName 账号 * @return */ @Override public boolean passwordFreeLogin(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); BladeUser user = null; //不存在就请求 if(Func.isEmpty(authToken)){ // 免密登录接口地址 String loginUrl = "http://localhost:"+this.getGatewayPort("ubcs-gateway")+"/ubcs-auth/oauth/token"; // 请求ubcs-auth服务获取token,先设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.set("Authorization", "Basic c3dvcmQ6c3dvcmRfc2VjcmV0"); headers.set("Tenant-Id", pwdFreeTenantId); //设置请求体参数 MultiValueMap parameters = new LinkedMultiValueMap(); 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()); } //拿到响应体其中包含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); } // 解析token存放进attr中 String token2 = JwtUtil.getToken(authToken); user = this.getUser(token2); //request.setAttribute("Blade-Auth",token); request.setAttribute("_BLADE_USER_REQUEST_ATTR_",user); return true; } /** * 根据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; } }