123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /*
- * Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the dreamlu.net developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: Chill 庄骞 (smallchill@163.com)
- */
- package org.springblade.auth.service;
- import io.jsonwebtoken.Claims;
- import lombok.AllArgsConstructor;
- import lombok.SneakyThrows;
- import org.apache.commons.lang.StringUtils;
- import org.springblade.auth.constant.AuthConstant;
- import org.springblade.auth.utils.TokenUtil;
- import org.springblade.common.cache.CacheNames;
- import org.springblade.core.jwt.JwtUtil;
- 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.utils.*;
- import org.springblade.system.cache.ParamCache;
- import org.springblade.system.entity.Tenant;
- import org.springblade.system.feign.ISysClient;
- import org.springblade.system.user.entity.User;
- import org.springblade.system.user.entity.UserInfo;
- import org.springblade.system.user.enums.UserEnum;
- import org.springblade.system.user.feign.IUserClient;
- import org.springframework.security.core.authority.AuthorityUtils;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.core.userdetails.UsernameNotFoundException;
- import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
- import org.springframework.stereotype.Service;
- import javax.servlet.http.HttpServletRequest;
- import java.time.Duration;
- import java.util.List;
- /**
- * 用户信息
- *
- * @author Chill
- */
- @Service
- @AllArgsConstructor
- public class BladeUserDetailsServiceImpl implements UserDetailsService {
- public static final Integer FAIL_COUNT = 5;
- public static final String FAIL_COUNT_VALUE = "account.failCount";
- private final IUserClient userClient;
- private final ISysClient sysClient;
- private final BladeRedis bladeRedis;
- private final JwtProperties jwtProperties;
- @Override
- @SneakyThrows
- public BladeUserDetails loadUserByUsername(String username) {
- HttpServletRequest request = WebUtil.getRequest();
- // 获取用户绑定ID
- String headerDept = request.getHeader(TokenUtil.DEPT_HEADER_KEY);
- String headerRole = request.getHeader(TokenUtil.ROLE_HEADER_KEY);
- // 获取租户ID
- String headerTenant = request.getHeader(TokenUtil.TENANT_HEADER_KEY);
- String paramTenant = request.getParameter(TokenUtil.TENANT_PARAM_KEY);
- String password = request.getParameter(TokenUtil.PASSWORD_KEY);
- String grantType = request.getParameter(TokenUtil.GRANT_TYPE_KEY);
- // 判断租户请求头
- if (StringUtil.isAllBlank(headerTenant, paramTenant)) {
- throw new UserDeniedAuthorizationException(TokenUtil.TENANT_NOT_FOUND);
- }
- // 判断令牌合法性
- if (!judgeRefreshToken(grantType, request)) {
- throw new UserDeniedAuthorizationException(TokenUtil.TOKEN_NOT_PERMISSION);
- }
- // 指定租户ID
- String tenantId = StringUtils.isBlank(headerTenant) ? paramTenant : headerTenant;
- // 判断登录是否锁定
- int count = getFailCount(tenantId, username);
- int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
- 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 = null;
- // 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
- 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()); //APP
- } else if (userType.equals(UserEnum.ARCHIVES.getName())) {
- result = userClient.userInfo(tenantId, username, UserEnum.ARCHIVES.getName()); //档案
- } else if (userType.equals(UserEnum.MANAGER.getName())) {
- result = userClient.userInfo(tenantId, username, UserEnum.MANAGER.getName()); //后管
- } else if (userType.equals(UserEnum.HAC.getName())) {
- result = userClient.userInfo(tenantId, username, UserEnum.HAC.getName()); //后管
- }
- //TODO
- // 判断返回信息
- assert result != null;
- if (result.isSuccess()) {
- UserInfo userInfo = result.getData();
- if (userInfo == null){
- throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
- }
- User user = userInfo.getUser();
- // 用户不存在,但提示用户名与密码错误并锁定账号
- if (user == null || user.getId() == null) {
- setFailCount(tenantId, username, count);
- throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
- }
- //用户存在但为封禁状态status=0,禁止登陆
- if (user.getStatus() == 0) {
- throw new UserDeniedAuthorizationException(TokenUtil.USER_STATUS_BAN);
- }
- // 用户存在但密码错误,超过次数则锁定账号
- 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);
- }
- /* 校验登陆账号权限,客户端填报、试验userType=1,app端userType=2,档案userType=3,后管userType=4 ,管控userType=5 ,征拆userType=6 */
- if (user.getUserType().contains(("1"))
- || user.getUserType().contains(("2"))
- || user.getUserType().contains(("3"))
- || user.getUserType().contains(("4"))
- || user.getUserType().contains(("5"))
- || user.getUserType().contains(("6"))
- || user.getUserType().contains(("7"))
- || user.getUserType().contains(("8"))
- ) {
- if (!("1,2,3,4,5,6,7,8").equals(user.getUserType())) {
- //如果不是全部权限,那么分批校验登陆平台权限
- this.judgeLoginPermission(user);
- }
- } else {
- throw new UserDeniedAuthorizationException(TokenUtil.USER_ACCOUNT_NO_TYPE);
- }
- // 多部门情况下指定单部门
- 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);
- return new BladeUserDetails(user.getId(), user.getPhone(),
- 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());
- }
- }
- /**
- * 获取账号错误次数
- *
- * @param tenantId 租户id
- * @param username 账号
- * @return int
- */
- private int getFailCount(String tenantId, String username) {
- return Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username)), 0);
- }
- /**
- * 设置账号错误次数
- *
- * @param tenantId 租户id
- * @param username 账号
- * @param count 次数
- */
- private void setFailCount(String tenantId, String username, int count) {
- bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
- }
- /**
- * 清空账号错误次数
- *
- * @param tenantId 租户id
- * @param username 账号
- */
- private void delFailCount(String tenantId, String username) {
- bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username));
- }
- /**
- * 校验refreshToken合法性
- *
- * @param grantType 认证类型
- * @param request 请求
- */
- private boolean judgeRefreshToken(String grantType, HttpServletRequest request) {
- if (jwtProperties.getState() && jwtProperties.getSingle() && StringUtil.equals(grantType, TokenUtil.REFRESH_TOKEN_KEY)) {
- String refreshToken = request.getParameter(TokenUtil.REFRESH_TOKEN_KEY);
- Claims claims = JwtUtil.parseJWT(refreshToken);
- String tenantId = String.valueOf(claims.get("tenant_id"));
- String userId = String.valueOf(claims.get("user_id"));
- String token = JwtUtil.getRefreshToken(tenantId, userId, refreshToken);
- return StringUtil.equalsIgnoreCase(token, refreshToken);
- }
- return true;
- }
- /**
- * 校验登陆账号权限
- *
- * @param user user信息
- * @author liuyc
- */
- private void judgeLoginPermission(User user) {
- //获取平台信息
- String clientId = TokenUtil.getClientIdFromHeader();
- String result = "0";
- if (clientId != null) {
- switch (clientId) {
- case "client":
- result = "1"; //WEB = 客户端
- break;
- case "uni-app":
- result = "2"; //APP = APP端
- break;
- case "archives":
- result = "3"; //archives = 档案
- break;
- case "saber":
- result = "4"; //manger = 后管
- break;
- case "hac":
- result = "5"; //hac = 成本管控系统
- break;
- case "lar":
- result = "6"; //lar = 征拆系统
- break;
- case "measure":
- result = "7"; //measure = 计量系统
- break;
- case "secure":
- result = "8"; //secure = 安全
- break;
- }
- }
- if ((("1").equals(result) && user.getUserType().contains("1")) //web
- || (("2").equals(result) && user.getUserType().contains("2")) //app
- || (("3").equals(result) && user.getUserType().contains("3")) //档案
- || (("4").equals(result) && user.getUserType().contains("4")) //后管
- || (("5").equals(result) && user.getUserType().contains("5")) // 成本管控系统
- || (("6").equals(result) && user.getUserType().contains("6")) // 征拆系统
- || (("7").equals(result) && user.getUserType().contains("7")) // 计量系统
- || (("8").equals(result) && user.getUserType().contains("8")) // 安全
- ) {
- //放行
- return;
- }
- throw new UserDeniedAuthorizationException(TokenUtil.USER_ACCOUNT_NO_PERMISSION);
- }
- }
|