| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | | |
| | | /** |
| | | * 用户信息 |
| | |
| | | * @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 |
| | |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | } |