content: package com.seezoon.admin.modules.sys.security;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Objects;
  import java.util.Optional;
  
  import javax.servlet.http.HttpServletRequest;
  
  import org.apache.commons.lang3.StringUtils;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.security.authentication.DisabledException;
  import org.springframework.security.authentication.LockedException;
  import org.springframework.security.core.GrantedAuthority;
  import org.springframework.security.core.userdetails.UserDetails;
  import org.springframework.security.core.userdetails.UserDetailsService;
  import org.springframework.security.core.userdetails.UsernameNotFoundException;
  import org.springframework.util.CollectionUtils;
  import org.springframework.web.context.request.RequestContextHolder;
  import org.springframework.web.context.request.ServletRequestAttributes;
  
  import com.seezoon.admin.framework.file.FileService;
  import com.seezoon.admin.modules.sys.dto.UserInfo;
  import com.seezoon.admin.modules.sys.security.constant.LockType;
  import com.seezoon.admin.modules.sys.security.constant.LoginType;
  import com.seezoon.admin.modules.sys.security.data.DataScope;
  import com.seezoon.admin.modules.sys.service.SysUserService;
  import com.seezoon.dao.framework.constants.EntityStatus;
  import com.seezoon.dao.modules.sys.entity.SysMenu;
  import com.seezoon.dao.modules.sys.entity.SysRole;
  import com.seezoon.dao.modules.sys.entity.SysUser;
  import com.seezoon.framework.exception.BusinessException;
  import com.seezoon.framework.utils.IpUtil;
  import com.seezoon.generator.plan.TablePlan;
  
  import cn.binarywang.wx.miniapp.api.WxMaService;
  import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
  import lombok.SneakyThrows;
  
  /**
   * 用户加载逻辑
   *
   * @author hdf
   */
  public class AdminUserDetailsServiceImpl implements UserDetailsService {
  
      @Autowired
      private UserService userService;
      @Autowired
      private SysUserService sysUserService;
      @Autowired
      private FileService fileService;
      @Autowired
      private LoginSecurityService loginSecurityService;
  
      @Autowired
      private WxMaService wxMaService;
  
      @SneakyThrows
      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
          HttpServletRequest request =
              ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
  
          String remoteIp = IpUtil.getRemoteIp(request);
          boolean ipLocked = loginSecurityService.getIpLockStrategy().isLocked(remoteIp);
          if (ipLocked) {
              throw new LockedException(LockType.IP.name());
          }
          if (StringUtils.isBlank(username)) {
              throw new UsernameNotFoundException("username is empty");
          }
  
          // 获取登录标识
          final String type = request.getParameter("type");
          SysUser user = null;
          if (StringUtils.isNotEmpty(type)) {
              user = this.thirdLogin(type, username);
              if (null == user) {
                  throw new UsernameNotFoundException("user not found");
              }
              username = user.getUsername();
              user.setPassword(AdminPasswordEncoder.NONE_PASSWORD);
          } else {
              boolean locked = loginSecurityService.getUsernameLockStrategy().isLocked(username);
              if (locked) {
                  throw new LockedException(LockType.USERNAME.name());
              }
              user = sysUserService.findByUsername(username);
              if (null == user) {
                  throw new UsernameNotFoundException(username + "  not found");
              }
          }
  
          if (EntityStatus.INVALID.status() == user.getStatus()) {
              throw new DisabledException(username + " disabled");
          }
  
          // 角色
          List<SysRole> userRoles = userService.findRolesByUserId(user.getId());
  
          UserInfo userInfo = new UserInfo(user.getId(), user.getDeptId(), user.getUsername(), user.getName());
          userInfo.setDeptName(user.getDeptName());
          userInfo.setPhoto(fileService.getUrl(user.getPhoto()));
          userInfo.setDsf(this.getDsf(userRoles, user.getId(), user.getDeptId()));
          // 角色及权限信息登录成功后放入
          AdminUserDetails adminUserDetails = new AdminUserDetails(userInfo, username, user.getPassword());
          adminUserDetails.setAuthorities(getAuthorities(userRoles, user.getId()));
          return adminUserDetails;
      }
  
      @SneakyThrows
      private SysUser thirdLogin(String type, String username) throws UsernameNotFoundException {
          SysUser user = null;
          if (LoginType.MP_WEIXIN.name().equals(type)) {
              WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(username);
              // 如果是多公众号 小程序 一起用在公众平台绑定后使用unionId.
              user = sysUserService.findByOpenId(wxMaJscode2SessionResult.getOpenid());
          } else {
              throw new BusinessException("un support login type");
          }
  
          return user;
      }
  
      /**
       *
       * @return
       */
      private List<GrantedAuthority> getAuthorities(List<SysRole> userRoles, Integer userId) {
          List<GrantedAuthority> authorities = new ArrayList<>();
  
          userRoles.stream().filter(v -> StringUtils.isNotBlank(v.getCode())).forEach(v -> {
              authorities.add(new UserGrantedAuthority(v.getCode(), true));
          });
          List<SysMenu> userMenus = userService.findMenusByUserId(userId);
          userMenus.stream().filter(v -> StringUtils.isNotBlank(v.getPermission())).forEach(v -> {
              authorities.add(new UserGrantedAuthority(v.getPermission()));
          });
          return authorities;
      }
  
      private String getDsf(List<SysRole> userRoles, Integer userId, Integer deptId) {
          if (SecurityUtils.isSuperAdmin(userId) || CollectionUtils.isEmpty(userRoles) || Objects.isNull(deptId)) {
              return null;
          }
          Optional<Integer> minOptional =
              userRoles.stream().map(SysRole::getDataScope).distinct().min(Integer::compareTo);
          if (!minOptional.isPresent()) {
              return null;
          }
          String defaultTableAliasPrefix = TablePlan.DEFAULT_TABLE_ALIAS_PREFIX;
          Integer dataScope = minOptional.get();
          if (Objects.equals(dataScope, DataScope.ALL.code())) { // 全部
              return null;
          } else if (Objects.equals(dataScope, DataScope.SELF_DEPT.code())) { // 本部门
              return " AND EXISTS (SELECT 1 FROM sys_user _dsf_sys_user WHERE _dsf_sys_user.dept_id = " + deptId
                  + " AND  " + defaultTableAliasPrefix + "create_by = _dsf_sys_user.create_by) ";
          } else if (Objects.equals(dataScope, DataScope.SELF_DEPT_AND_BELOW.code())) { // 本部门及以下
              return " AND EXISTS (SELECT 1 FROM sys_user _dsf_sys_user WHERE (_dsf_sys_user.dept_id = " + deptId
                  + " OR _dsf_sys_user.dept_id like '%/" + deptId + "/%') AND  " + defaultTableAliasPrefix
                  + "create_by = _dsf_sys_user.create_by) ";
          } else if (Objects.equals(dataScope, DataScope.SELF.code())) { // 本人
              return " AND " + defaultTableAliasPrefix + "create_by = " + userId + " ";
          }
          return null;
      }
  
  }
  