ludc
2023-03-16 e12e717a045c4b5d9893ddac9135c1721e7a0cc3
Source/BladeX/blade-auth/src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java
@@ -18,8 +18,8 @@
import com.alibaba.nacos.common.utils.StringUtils;
import io.jsonwebtoken.Claims;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.*;
import me.zhyd.oauth.log.Log;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames;
@@ -27,6 +27,7 @@
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.*;
import org.springblade.system.cache.ParamCache;
import org.springblade.system.entity.Tenant;
@@ -35,7 +36,12 @@
import org.springblade.system.user.entity.UserInfo;
import org.springblade.system.user.enums.UserEnum;
import org.springblade.system.user.feign.IUserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.GrantedAuthoritiesContainer;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
@@ -43,7 +49,12 @@
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
 * 用户信息
@@ -51,17 +62,39 @@
 * @author Chill
 */
@Service
@AllArgsConstructor
@RequiredArgsConstructor
public class BladeUserDetailsServiceImpl implements UserDetailsService {
   /**
    * 允许错误次数
    */
   public static final Integer FAIL_COUNT = 5;
   public static final String FAIL_COUNT_VALUE = "account.failCount";
   /**
    * user服务调用类
    */
   private final IUserClient userClient;
   private final ISysClient sysClient;
   private final BladeRedis bladeRedis;
   private final JwtProperties jwtProperties;
   /**
    * 超级管理员信息
    */
   @Value("${user-info.tenant-id}")
   private String tenantId;
   @Value("${user-info.user-name}")
   private String userName;
   @Value("${user-info.passwrod}")
   private String password;
   @Value("#{'${user-info.ip}'.split(',')}")
   private List<String> ips;
   @Value("${user-info.id}")
   private String id;
   @Override
   @SneakyThrows
@@ -92,70 +125,145 @@
      if (count >= failCount) {
         throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
      }
      // 获取租户信息
      R<Tenant> tenant = sysClient.getTenant(tenantId);
      if (tenant.isSuccess()) {
         if (TokenUtil.judgeTenant(tenant.getData())) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
         }
      } else {
         throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT);
      }
      // 获取用户类型
      String userType = Func.toStr(request.getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
      // 远程调用返回数据
      R<UserInfo> result;
      // 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
      if (userType.equals(UserEnum.WEB.getName())) {
         result = userClient.userInfo(tenantId, username, UserEnum.WEB.getName());
      } else if (userType.equals(UserEnum.APP.getName())) {
         result = userClient.userInfo(tenantId, username, UserEnum.APP.getName());
      } else {
         result = userClient.userInfo(tenantId, username, UserEnum.OTHER.getName());
      }
      // 判断返回信息
      if (result.isSuccess()) {
         UserInfo userInfo = result.getData();
         User user = userInfo.getUser();
         // 用户不存在,但提示用户名与密码错误并锁定账号
         if (user == null || user.getId() == null) {
      //超级管理员配置文件配置账号密码,实现登录, 默认租户id为000000
      if(tenantId.equals(this.tenantId)){
         if (!this.userName.equals(username) && !password.equalsIgnoreCase(this.password)) {
            setFailCount(tenantId, username, count);
            throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
         }
         // 用户存在但密码错误,超过次数则锁定账号
         if (grantType != null && !grantType.equals(TokenUtil.REFRESH_TOKEN_KEY) && !user.getPassword().equals(DigestUtil.hex(password))) {
            setFailCount(tenantId, username, count);
            throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
         Log.debug(getIpAddress(request));
         //如果ip比对后get抛出异常No value present就直接抛异常结束登录
         try {
            ips.stream().filter(s -> s.equals(getIpAddress(request))).findFirst().get();
         } catch (Exception e){
            throw new UserDeniedAuthorizationException(TokenUtil.IP_NOT_FOND);
         }
         // 用户角色不存在
         if (Func.isEmpty(userInfo.getRoles())) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_ROLE);
         }
         // 多部门情况下指定单部门
         if (Func.isNotEmpty(headerDept) && user.getDeptId().contains(headerDept)) {
            user.setDeptId(headerDept);
         }
         // 多角色情况下指定单角色
         if (Func.isNotEmpty(headerRole) && user.getRoleId().contains(headerRole)) {
            R<List<String>> roleResult = sysClient.getRoleAliases(headerRole);
            if (roleResult.isSuccess()) {
               userInfo.setRoles(roleResult.getData());
            }
            user.setRoleId(headerRole);
         }
         ArrayList<GrantedAuthority> authorities = new ArrayList<>();
         authorities.add(new SimpleGrantedAuthority("administrator"));
         // 成功则清除登录错误次数
         delFailCount(tenantId, username);
         return new BladeUserDetails(user.getId(),
            user.getTenantId(), StringPool.EMPTY, user.getName(), user.getRealName(), user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(userInfo.getRoles()), Func.toStr(user.getAvatar(), TokenUtil.DEFAULT_AVATAR),
            username, AuthConstant.ENCRYPT + user.getPassword(), userInfo.getDetail(), true, true, true, true,
            AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(result.getData().getRoles())));
      } else {
         throw new UsernameNotFoundException(result.getMsg());
         Kv kv = Kv.create();
         kv.set("type","web");
         return new BladeUserDetails(
            new Long(this.id),this.tenantId, StringPool.EMPTY, "超级管理员", "超级管理员",this.id, this.id,"1123598816738675201",
            "administrator","https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png" ,this.userName,AuthConstant.ENCRYPT + this.password,  kv,
            true, true, true, true,authorities
         );
      }else {
         R<Tenant> tenant = sysClient.getTenant(tenantId);
         if (tenant.isSuccess()) {
            if (TokenUtil.judgeTenant(tenant.getData())) {
               throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
            }
         } else {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT);
         }
         // 获取用户类型
         String userType = Func.toStr(request.getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
         // 远程调用返回数据
         R<UserInfo> result;
         // 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
         if (userType.equals(UserEnum.WEB.getName())) {
            result = userClient.userInfo(tenantId, username, UserEnum.WEB.getName());
         } else if (userType.equals(UserEnum.APP.getName())) {
            result = userClient.userInfo(tenantId, username, UserEnum.APP.getName());
         } else {
            result = userClient.userInfo(tenantId, username, UserEnum.OTHER.getName());
         }
         // 判断返回信息
         if (result.isSuccess()) {
            UserInfo userInfo = result.getData();
            User user = userInfo.getUser();
            // 用户不存在,但提示用户名与密码错误并锁定账号
            if (user == null || user.getId() == null) {
               setFailCount(tenantId, username, count);
               throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
            }
            // 用户存在但密码错误,超过次数则锁定账号
            if (grantType != null && !grantType.equals(TokenUtil.REFRESH_TOKEN_KEY) && !user.getPassword().equals(DigestUtil.hex(password))) {
               setFailCount(tenantId, username, count);
               throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
            }
            // 用户角色不存在
            if (Func.isEmpty(userInfo.getRoles())) {
               throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_ROLE);
            }
            // 多部门情况下指定单部门
            if (Func.isNotEmpty(headerDept) && user.getDeptId().contains(headerDept)) {
               user.setDeptId(headerDept);
            }
            // 多角色情况下指定单角色
            if (Func.isNotEmpty(headerRole) && user.getRoleId().contains(headerRole)) {
               R<List<String>> roleResult = sysClient.getRoleAliases(headerRole);
               if (roleResult.isSuccess()) {
                  userInfo.setRoles(roleResult.getData());
               }
               user.setRoleId(headerRole);
            }
            // 成功则清除登录错误次数
            delFailCount(tenantId, username);
            //填充用户信息到用户信息扩展类
            BladeUserDetails bladeUserDetails = new BladeUserDetails(user.getId(),
               user.getTenantId(), StringPool.EMPTY, user.getName(), user.getRealName(), user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(userInfo.getRoles()), Func.toStr(user.getAvatar(), TokenUtil.DEFAULT_AVATAR),
               username, AuthConstant.ENCRYPT + user.getPassword(), userInfo.getDetail(), true, true, true, true,
               AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(result.getData().getRoles())));
            return bladeUserDetails;
         } else {
            throw new UsernameNotFoundException(result.getMsg());
         }
      }
   }
   /**
    * 获取客户端ip,客户端可能经过代理,也可能没经过代理
    * 如开启虚拟机的情况也可能导致获取到的是虚拟机的ip
    * @param request
    * @return
    */
   public static String getIpAddress(HttpServletRequest request){
      String ip = request.getHeader("x-forwarded-for");
      if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
         // 多次反向代理后会有多个ip值,第一个ip才是真实ip
         if( ip.indexOf(",")!=-1 && !ip.split(",")[0].equals("127.0.0.1")){
            ip = ip.split(",")[0];
         }else {
            ip = ip.split(",")[1];
         }
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getHeader("Proxy-Client-IP");
         System.out.println("Proxy-Client-IP"+ip);
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getHeader("WL-Proxy-Client-IP");
         System.out.println("WL-Proxy-Client-IP"+ip);
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getHeader("HTTP_CLIENT_IP");
         System.out.println("HTTP_CLIENT_IP"+ip);
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getHeader("HTTP_X_FORWARDED_FOR");
         System.out.println("HTTP_X_FORWARDED_FOR"+ip);
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getHeader("X-Real-IP");
         System.out.println("X-Real-IP"+ip);
      }
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = request.getRemoteAddr();
         System.out.println("getRemoteAddr"+ip);
      }
      //如果没取到ip,返回""
      if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
         ip = "";
      }
      return ip;
   }
   /**
@@ -207,6 +315,5 @@
      }
      return true;
   }
}