Compare commits

...

37 Commits

Author SHA1 Message Date
sxu bfd6ec188b OAUTH 2025-05-19 10:29:21 +08:00
sxu a93959f1f2 OAUTH 2025-05-19 09:28:00 +08:00
sxu 4178670171 sys.visit.tokentime解析出错加保护 2025-05-16 18:29:52 +08:00
sxu 87c9b768a5 username登录用户名密码密文解密 2025-05-16 18:18:39 +08:00
sxu 57c87d470f 空指针保护 2025-05-16 09:57:09 +08:00
sxu 01ce4bfe53 安徽省公司短信平台 2025-05-08 15:00:06 +08:00
sxu 46c1c10175 安徽省公司短信平台 2025-05-08 11:02:16 +08:00
sxu a75483d0bb 安徽省公司短信平台 2025-05-07 18:35:53 +08:00
sxu 95d4e9ba5c 安徽省公司短信平台 2025-05-07 17:32:01 +08:00
sxu 1b918cbbe7 Revert "安徽省公司短信平台"
This reverts commit 40576bf75b.
2025-05-07 16:26:56 +08:00
sxu 40576bf75b 安徽省公司短信平台 2025-05-07 16:05:24 +08:00
sxu 5b52697a78 Revert "配置文件"
This reverts commit 818d8af74b.
2025-04-28 12:08:36 +08:00
sxu 818d8af74b 配置文件 2025-04-28 10:48:02 +08:00
sxu 98871dd611 user listByPost 2025-04-23 09:03:49 +08:00
sxu 4d7c936bab deptUserTree 2025-04-17 15:05:02 +08:00
sxu 10a7d86281 deptTreeByPost 2025-04-16 20:17:11 +08:00
sxu 6f1315d73b 组织人员树避免死循环 2025-04-16 11:17:59 +08:00
sxu cb43fe4523 根据roleNames获取用户列表 2025-04-15 21:08:31 +08:00
sxu 49b8a7a7ce 根据roleNames获取用户列表 2025-04-15 19:14:51 +08:00
sxu 960d76f4f0 根据roleNames获取用户列表 2025-04-15 16:33:56 +08:00
sxu 8fa55acb45 根据roleKey获取用户列表 2025-04-15 15:35:18 +08:00
sxu 0c631ec70f 根据userIds获取用户列表 2025-04-14 21:56:52 +08:00
sxu 54f3855a28 运检食堂需求 2025-04-11 10:58:37 +08:00
sxu 0980714dfb smart_canteen_local 2025-04-06 20:31:32 +08:00
sxu 1fe1373832 Revert "sys_user add columes"
This reverts commit 7e6b964f0b.
2025-03-13 12:19:37 +08:00
sxu 7e6b964f0b sys_user add columes 2025-03-13 12:18:46 +08:00
sxu 927a68fa63 LoginUser 2025-02-14 19:34:26 +08:00
sxu 491ce132d6 LoginUser 2025-02-14 16:04:07 +08:00
sxu 60aedf35ed Revert "LoginUser"
This reverts commit 2bf4368c87.
2025-02-14 15:46:29 +08:00
sxu 1d6e65af0f Revert "LoginUser"
This reverts commit 4eeeb80e18.
2025-02-14 15:46:15 +08:00
sxu f3a9db9e6c Revert "LoginUser"
This reverts commit d062ffc4c2.
2025-02-14 15:45:55 +08:00
sxu d062ffc4c2 LoginUser 2025-02-14 15:08:12 +08:00
sxu 4eeeb80e18 LoginUser 2025-02-14 14:30:10 +08:00
sxu 2bf4368c87 LoginUser 2025-02-14 14:19:38 +08:00
sxu 4133365bdf LoginUser 2025-02-14 14:00:16 +08:00
sxu c4c313c691 LoginUser 2025-02-13 13:13:59 +08:00
sxu 1c5c2471c4 combine custauth 2025-02-13 12:38:47 +08:00
36 changed files with 938 additions and 35 deletions

View File

@ -31,6 +31,8 @@ public interface RemoteUserService {
@GetMapping("/user/list}") @GetMapping("/user/list}")
public TableDataInfo list(SysUser user, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); public TableDataInfo list(SysUser user, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
@PostMapping("/user/listByPost")
public TableDataInfo listByPost(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/** /**
* 通过用户名查询用户信息 * 通过用户名查询用户信息
@ -52,6 +54,15 @@ public interface RemoteUserService {
@GetMapping("/user/infoPhoto/{phone}") @GetMapping("/user/infoPhoto/{phone}")
public R<LoginUser> getUserInfoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); public R<LoginUser> getUserInfoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 通过用户名查询用户信息
*
* @param phone 手机号
* @param source 请求来源
* @return 结果
*/
@GetMapping("/user/custInfoPhoto/{phone}")
public R<LoginUser> getCustInfoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/** /**
* 通过用户名查询用户信息 * 通过用户名查询用户信息
@ -169,6 +180,9 @@ public interface RemoteUserService {
@GetMapping("/user/deptTree") @GetMapping("/user/deptTree")
public AjaxResult deptTree(SysDept dept, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); public AjaxResult deptTree(SysDept dept, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
@PostMapping("/user/deptTreeByPost")
public AjaxResult deptTreeByPost(@RequestBody SysDept sysDept, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/** /**
* 查询部门人员树列表 * 查询部门人员树列表
* *

View File

@ -112,6 +112,8 @@ public class SysDept extends BaseEntity {
*/ */
private String logo; private String logo;
private Long nodeId;
//公司管理员用户ID //公司管理员用户ID
private Long adminUserId; private Long adminUserId;
@ -203,6 +205,14 @@ public class SysDept extends BaseEntity {
this.logo = logo; this.logo = logo;
} }
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public Long getAdminUserId() { public Long getAdminUserId() {
return adminUserId; return adminUserId;
} }

View File

@ -6,6 +6,8 @@ import com.bonus.common.core.annotation.Excel.Type;
import com.bonus.common.core.annotation.Excels; import com.bonus.common.core.annotation.Excels;
import com.bonus.common.core.web.domain.BaseEntity; import com.bonus.common.core.web.domain.BaseEntity;
import com.bonus.common.core.xss.Xss; import com.bonus.common.core.xss.Xss;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -51,6 +53,8 @@ public class SysUser extends BaseEntity {
@Excel(name = "登录名称") @Excel(name = "登录名称")
private String userName; private String userName;
private String[] userNames;
/** /**
* 用户昵称 * 用户昵称
*/ */
@ -137,6 +141,11 @@ public class SysUser extends BaseEntity {
*/ */
private Long roleId; private Long roleId;
/**
* 用户组
*/
private Long[] userIds;
/** /**
* 登录权限 * 登录权限
*/ */
@ -153,6 +162,19 @@ public class SysUser extends BaseEntity {
/**是否内置0内置1非内置*/ /**是否内置0内置1非内置*/
private String isBuiltIn = "1"; private String isBuiltIn = "1";
private boolean pagination;
@ApiModelProperty("人员id")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long custId;
@ApiModelProperty("人员姓名")
private String custName;
@ApiModelProperty("人员编号")
private String custNum;
@ApiModelProperty("人脸照片地址")
private String custPhotoUrl;
public SysUser() { public SysUser() {
} }
@ -215,6 +237,14 @@ public class SysUser extends BaseEntity {
this.userName = userName; this.userName = userName;
} }
public String[] getUserNames() {
return userNames;
}
public void setUserNames(String[] userNames) {
this.userNames = userNames;
}
@Email(message = "邮箱格式不正确") @Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
public String getEmail() { public String getEmail() {
@ -330,6 +360,14 @@ public class SysUser extends BaseEntity {
this.roleId = roleId; this.roleId = roleId;
} }
public Long[] getUserIds() {
return userIds;
}
public void setUserIds(Long[] userIds) {
this.userIds = userIds;
}
public String getLoginType() { public String getLoginType() {
return loginType; return loginType;
} }
@ -354,6 +392,38 @@ public class SysUser extends BaseEntity {
this.isPermanent = isPermanent; this.isPermanent = isPermanent;
} }
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustNum() {
return custNum;
}
public void setCustNum(String custNum) {
this.custNum = custNum;
}
public String getCustPhotoUrl() {
return custPhotoUrl;
}
public void setCustPhotoUrl(String custPhotoUrl) {
this.custPhotoUrl = custPhotoUrl;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@ -387,4 +457,12 @@ public class SysUser extends BaseEntity {
public void setIsBuiltIn(String isBuiltIn) { public void setIsBuiltIn(String isBuiltIn) {
this.isBuiltIn = isBuiltIn; this.isBuiltIn = isBuiltIn;
} }
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
} }

View File

@ -38,6 +38,11 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
return getDataTableError(new ArrayList<SysUser>()); return getDataTableError(new ArrayList<SysUser>());
} }
@Override
public TableDataInfo listByPost(SysUser user, String source) {
return getDataTableError(new ArrayList<SysUser>());
}
@Override @Override
public R<LoginUser> getUserInfo(String username, String source) public R<LoginUser> getUserInfo(String username, String source)
{ {
@ -56,6 +61,11 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
return R.fail("获取用户失败:" + throwable.getMessage()); return R.fail("获取用户失败:" + throwable.getMessage());
} }
@Override
public R<LoginUser> getCustInfoByPhone(String phone, String source) {
return R.fail("获取用户失败:" + throwable.getMessage());
}
/** /**
* 通过用户名查询用户信息 * 通过用户名查询用户信息
* *
@ -136,6 +146,11 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
return AjaxResult.error("获取部门权限下的部门树列表:" + throwable.getMessage()); return AjaxResult.error("获取部门权限下的部门树列表:" + throwable.getMessage());
} }
@Override
public AjaxResult deptTreeByPost(SysDept sysDept, String source) {
return AjaxResult.error("获取部门权限下的部门树列表:" + throwable.getMessage());
}
@Override @Override
public AjaxResult deptUserTree(SysUser sysUser, String source) { public AjaxResult deptUserTree(SysUser sysUser, String source) {
return AjaxResult.error("查询部门人员树列表:" + throwable.getMessage()); return AjaxResult.error("查询部门人员树列表:" + throwable.getMessage());

View File

@ -3,6 +3,8 @@ package com.bonus.system.api.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.Set; import java.util.Set;
import com.bonus.system.api.domain.SysUser; import com.bonus.system.api.domain.SysUser;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
/** /**
* 用户信息 * 用户信息
@ -23,6 +25,12 @@ public class LoginUser implements Serializable
*/ */
private Long userid; private Long userid;
/**
* 客户id
*/
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long custId;
/** /**
* 用户名 * 用户名
*/ */
@ -58,6 +66,12 @@ public class LoginUser implements Serializable
*/ */
private SysUser sysUser; private SysUser sysUser;
@ApiModelProperty("过期时间")
private Long expireIn;
@ApiModelProperty("是否登录")
private boolean isLogin;
public String getToken() public String getToken()
{ {
return token; return token;
@ -78,6 +92,14 @@ public class LoginUser implements Serializable
this.userid = userid; this.userid = userid;
} }
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getUsername() public String getUsername()
{ {
return username; return username;
@ -147,4 +169,20 @@ public class LoginUser implements Serializable
{ {
this.sysUser = sysUser; this.sysUser = sysUser;
} }
public Long getExpireIn() {
return expireIn;
}
public void setExpireIn(Long expireIn) {
this.expireIn = expireIn;
}
public boolean isLogin() {
return isLogin;
}
public void setLogin(boolean login) {
isLogin = login;
}
} }

Binary file not shown.

View File

@ -100,6 +100,25 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!-- 省公司短信平台sms-util -->
<dependency>
<groupId>com.ahsbd</groupId>
<artifactId>sms-util</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/sms-util-1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -108,6 +127,9 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions> <executions>
<execution> <execution>
<goals> <goals>

View File

@ -22,7 +22,15 @@ public enum LoginType {
/** /**
* 邮箱验证码 * 邮箱验证码
*/ */
EMAIL_OTP; EMAIL_OTP,
/**
* 客户手机号密码
*/
CUST_PHONE_PASSWORD,
/**
* 客户手机号验证码
*/
CUST_PHONE_OPT;
@JsonCreator @JsonCreator
public static LoginType fromString(String key) { public static LoginType fromString(String key) {

View File

@ -0,0 +1,67 @@
package com.bonus.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
// Configure the token store and JWT converter
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("your-256-bit-secret"); // Use a secure key in production
return converter;
}
// Configure security constraints on the token endpoint
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()") // Public key for token verification
.checkTokenAccess("isAuthenticated()") // Token validation endpoint
.allowFormAuthenticationForClients();
}
// Configure client details service
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id") // Your client ID
.secret(passwordEncoder.encode("client-secret")) // Your client secret
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(86400); // 24 hours
}
// Configure the endpoints
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
}

View File

@ -0,0 +1,132 @@
package com.bonus.auth.controller;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.RemoteUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@RequestMapping("/ticket")
public class TicketController {
@Resource
private RemoteUserService remoteUserService;
@Resource
public RedisTemplate<String, String> redisTemplate;
@Resource
private TokenStore tokenStore;
/**
* 获得用户tokenuserId当前时间加密的字符串
* 跳转第三方菜单时获取 登录凭证 Ticket
* 将Ticket记录在redis中设置时效 60s,记录用户id用户的token和当前时间
*/
@GetMapping("getUserTicket")
public String getUserTicket() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2Authentication) {
Object details = authentication.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails detail = (OAuth2AuthenticationDetails) details;
String tokenValue = detail.getTokenValue();
String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
Long userId = SecurityUtils.getUserId();
String ticket = tokenValue + "," + dateStr + "," + userId;
String encryptedString = Sm4Utils.encrypt(ticket);
if (encryptedString != null) {
String uuid = UuidUtils.generateUuid();
redisTemplate.opsForValue().set(uuid, encryptedString, 60, TimeUnit.SECONDS);
return uuid;
}
}
}
throw new RuntimeException("未知错误");
}
/**
* 登录凭证 Ticket校验
* 第三方系统拿到Ticket后需要校验该Ticket有效性校验通过返回用户信息
* @param ticket登录凭证
* @param appId第三方系统注册颁发的APPID唯一标识用来控制第三方系统的接入
* @return
*/
@GetMapping("validate")
public AjaxResult getUserInfo(String ticket, String appId) {
if (appId==null || "".equals(appId)) {
log.error("第三方系统Ticket校验失败: ticket{} 结果 :{} ",ticket,"APPID为空");
return new AjaxResult(10000, "APPID为空!");
}
if (ticket==null || "".equals(ticket)) {
log.error("第三方系统Ticket校验失败:appId{} 结果 :{} ",appId,"令牌为空");
return new AjaxResult(10001, "令牌为空!");
}
String encryptedString = redisTemplate.opsForValue().get(ticket);
if (StringUtils.isBlank(encryptedString)) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌已失效");
return new AjaxResult(10003, "令牌已失效!");
}
String realTicket = Sm4Utils.decrypt(encryptedString);
if (StringUtils.isBlank(realTicket)) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌解析错误");
return new AjaxResult(10004, "令牌解析错误!");
}
String[] ticketInfoArr = realTicket.split(",");
String tokenValue = ticketInfoArr[0];
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StringUtils.isEmpty(accessToken.getValue())) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"当前用户已离线,请重新登录");
return new AjaxResult(10005, "当前用户已离线,请重新登录!");
}
String userId = ticketInfoArr[2];
AjaxResult result = remoteUserService.getInfo(Long.parseLong(userId), SecurityConstants.INNER);
// Map<String, Object> resMap = new HashMap<>();
// resMap.put("userName", sysUser.getUserName());
// resMap.put("name", sysUser.getNickName());
// resMap.put("deptId", sysUser.getDeptId());
// resMap.put("deptName", sysUser.getDept() == null ? null : sysUser.getDept().getDeptName().replaceAll("YJ", ""));
//
// SysDept dept = sysUser.getDept();
// 特定的业务需求需要记录当前用户是否为运检站,并且返回 xx站
// if (dept != null) {
// if ("4".equals(dept.getDeptType()) && dept.getDeptName().contains("")) {
// resMap.put("businessDeptName", dept.getDeptName().replaceAll("YJ", ""));
// } else {
// resMap.put("businessDeptName", "");
// }
// } else {
// resMap.put("businessDeptName", "");
// }
log.info("第三方系统Ticket校验成功:appId{} ticket{} Ticket生成时间{}",appId,ticket,ticketInfoArr[1]);
return AjaxResult.success(result);
}
}

View File

@ -1,6 +1,5 @@
package com.bonus.auth.controller; package com.bonus.auth.controller;
import com.alibaba.fastjson.JSONObject;
import com.bonus.auth.config.LoginType; import com.bonus.auth.config.LoginType;
import com.bonus.auth.factory.LoginStrategyFactory; import com.bonus.auth.factory.LoginStrategyFactory;
import com.bonus.auth.form.LoginBody; import com.bonus.auth.form.LoginBody;
@ -12,6 +11,7 @@ import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException; import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.JwtUtils; import com.bonus.common.core.utils.JwtUtils;
import com.bonus.common.core.utils.StringUtils; import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.redis.service.RedisService; import com.bonus.common.redis.service.RedisService;
import com.bonus.common.security.auth.AuthUtil; import com.bonus.common.security.auth.AuthUtil;
@ -19,24 +19,19 @@ import com.bonus.common.security.service.TokenService;
import com.bonus.common.security.utils.SecurityUtils; import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.config.SystemConfig; import com.bonus.config.SystemConfig;
import com.bonus.system.api.RemoteConfigService; import com.bonus.system.api.RemoteConfigService;
import com.bonus.system.api.RemoteLogService;
import com.bonus.system.api.RemoteUserService; import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser; import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser; import com.bonus.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -136,7 +131,7 @@ public class TokenController {
if (strategy == null) { if (strategy == null) {
return R.fail("不支持的登录方式"); return R.fail("不支持的登录方式");
} }
if (form.getLoginType()== LoginType.EMAIL_OTP || form.getLoginType()== LoginType.PHONE_OTP ){ if (form.getLoginType()== LoginType.EMAIL_OTP || form.getLoginType()== LoginType.PHONE_OTP || form.getLoginType()== LoginType.CUST_PHONE_OPT){
form.setPassword(form.getVerificationCode()); form.setPassword(form.getVerificationCode());
} }
@ -154,8 +149,16 @@ public class TokenController {
LoginUser login = strategy.login(form.getUsername(), form.getPassword()); LoginUser login = strategy.login(form.getUsername(), form.getPassword());
logService.saveLogin(form.getUsername(), "登录", "登录成功", null, "成功"); logService.saveLogin(form.getUsername(), "登录", "登录成功", null, "成功");
return R.ok(tokenService.createToken(login));
if (LoginType.CUST_PHONE_PASSWORD.equals(form.getLoginType()) || LoginType.CUST_PHONE_OPT.equals(form.getLoginType())) {
Map<String, Object> map = tokenService.createCustToken(login);
login.setToken((String) map.get("access_token"));
login.setExpireIn((Long) map.get("expires_in"));
login.setLogin((boolean) map.get("isLogin"));
return R.ok(login);
} else {
return R.ok(tokenService.createToken(login));
}
} }
/** /**

View File

@ -31,6 +31,10 @@ public class LoginStrategyFactory {
strategyMap.put(LoginType.EMAIL_PASSWORD, strategy); strategyMap.put(LoginType.EMAIL_PASSWORD, strategy);
} else if (strategy instanceof EmailOtpLoginStrategy) { } else if (strategy instanceof EmailOtpLoginStrategy) {
strategyMap.put(LoginType.EMAIL_OTP, strategy); strategyMap.put(LoginType.EMAIL_OTP, strategy);
} else if (strategy instanceof CustPhonePasswordLoginStrategy) {
strategyMap.put(LoginType.CUST_PHONE_PASSWORD, strategy);
} else if (strategy instanceof CustPhoneOtpLoginStrategy) {
strategyMap.put(LoginType.CUST_PHONE_OPT, strategy);
} }
// 继续添加其他策略 // 继续添加其他策略
}); });

View File

@ -0,0 +1,48 @@
package com.bonus.auth.service;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.config.SystemConfig;
import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author bonus
*/
@Service
public class CustPhoneOtpLoginStrategy implements LoginStrategy {
@Resource
private SystemConfig systemConfig;
@Resource
private RemoteUserService remoteUserService;
@Resource
private PasswordValidatorService passwordValidatorService;
@Override
public LoginUser login(String phone, String otp) {
if (!systemConfig.getLoginConfig().isPhoneCode()) {
throw new ServiceException("用户不存在/验证码错误");
}
passwordValidatorService.checkPhoneCaptcha(phone, otp);
R<LoginUser> userResult = remoteUserService.getCustInfoByPhone(phone, SecurityConstants.INNER);
//验证用户是否存在
passwordValidatorService.validateUserResult(phone, userResult);
LoginUser userInfo = userResult.getData();
//SysUser user = userInfo.getSysUser();
//passwordValidatorService.validateApprovalStatus(phone, user);
// 验证用户状态
//passwordValidatorService.validateUserStatus(phone, user);
//passwordValidatorService.processLoginBlackList(user);
//返回信息
return userInfo;
}
}

View File

@ -0,0 +1,67 @@
package com.bonus.auth.service;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.encryption.AesEncryptUtil;
import com.bonus.config.SystemConfig;
import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author bonus
*/
@Service
public class CustPhonePasswordLoginStrategy implements LoginStrategy {
@Resource
private SystemConfig systemConfig;
@Resource
private RemoteUserService remoteUserService;
@Resource
private PasswordValidatorService passwordValidatorService;
@Resource
private SysPasswordService passwordService;
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
@Override
public LoginUser login(String phone, String password) {
if (!systemConfig.getLoginConfig().isPhonePassword()) {
throw new ServiceException("用户不存在/密码错误");
}
//通过手机号获取用户信息
R<LoginUser> userResult = remoteUserService.getCustInfoByPhone(phone, SecurityConstants.INNER);
//验证用户是否存在
passwordValidatorService.validateUserResult(phone, userResult);
//获取用户信息
LoginUser userInfo = userResult.getData();
SysUser user = userInfo.getSysUser();
//校验用户审批状态
//passwordValidatorService.validateApprovalStatus(user.getUserName(), user);
// 处理IP校验
//passwordValidatorService.validateIpBlacklist(user.getUserName());
// 验证密码
String decodedPassword = AesEncryptUtil.aesDecode(password);
if (!encoder.matches(decodedPassword, user.getPassword())) {
throw new ServiceException("密码错误");
}
//passwordService.validate(user, password, System.currentTimeMillis());
//校验用户启用状态
//passwordValidatorService.validateUserStatus(user.getUserName(), user);
//passwordValidatorService.processLoginBlackList(user);
//返回信息
return userInfo;
}
}

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R; import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException; import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.security.service.EmailService; import com.bonus.common.security.service.EmailService;
import com.bonus.common.security.service.SmsService;
import com.bonus.system.api.RemoteUserService; import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.model.LoginUser; import com.bonus.system.api.model.LoginUser;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;

View File

@ -5,7 +5,6 @@ import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException; import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.encryption.Sm4Utils; import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.security.service.EmailService; import com.bonus.common.security.service.EmailService;
import com.bonus.common.security.service.SmsService;
import com.bonus.config.SystemConfig; import com.bonus.config.SystemConfig;
import com.bonus.system.api.RemoteUserService; import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.model.LoginUser; import com.bonus.system.api.model.LoginUser;

View File

@ -0,0 +1,56 @@
package com.bonus.auth.service;
import com.bonus.common.core.constant.CacheConstants;
import com.bonus.common.core.exception.CaptchaException;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.VerificationCodeUtils;
import com.bonus.auth.utils.SmsUtils;
import com.bonus.common.redis.service.RedisService;
import com.bonus.common.security.config.VerificationCodeConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import static com.bonus.common.core.utils.VerificationCodeUtils.CodeType.NUMERIC;
/**
* @author bonus
*/
@Component
@Slf4j
public class SmsService {
@Resource
private VerificationCodeConfig verificationCodeConfig;
@Resource
private RedisService redisService;
/**
* 生成手机验证码
*
* @return AjaxResult
* @throws CaptchaException 自定义captcha 异常
*/
public void sendSimplePhone(String to) {
if (StringUtils.isEmpty(to)) {
throw new CaptchaException("手机号不能为空");
}
String code = VerificationCodeUtils.generateVerificationCode(NUMERIC);
String str = verificationCodeConfig.getContent().replace("<code>", code);
str = str.replace("<time>", verificationCodeConfig.getTime().toString());
String s = SmsUtils.sendMsgToSms(Arrays.asList(to), str);
log.error("省公司短信平台发送短信返回结果=" + s);
if (StringUtils.isNotEmpty(s)) {
if (s.contains(":200")) {
String verifyKey = CacheConstants.VERIFICATION_CODE + StringUtils.nvl(to, "");
redisService.setCacheObject(verifyKey, code, verificationCodeConfig.getTime(), TimeUnit.MINUTES);
} else {
throw new CaptchaException("获取短信失败");
}
} else {
throw new CaptchaException("获取短信失败");
}
}
}

View File

@ -1,5 +1,6 @@
package com.bonus.auth.service; package com.bonus.auth.service;
import com.bonus.auth.utils.SmsUtils;
import com.bonus.common.core.constant.CacheConstants; import com.bonus.common.core.constant.CacheConstants;
import com.bonus.common.core.constant.Constants; import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.domain.R; import com.bonus.common.core.domain.R;
@ -7,7 +8,6 @@ import com.bonus.common.core.exception.CaptchaException;
import com.bonus.common.core.exception.ServiceException; import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.StringUtils; import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.VerificationCodeUtils; import com.bonus.common.core.utils.VerificationCodeUtils;
import com.bonus.common.core.utils.sms.SmsUtils;
import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.redis.service.RedisService; import com.bonus.common.redis.service.RedisService;
import com.bonus.common.security.utils.SecurityUtils; import com.bonus.common.security.utils.SecurityUtils;
@ -19,6 +19,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@ -107,7 +108,7 @@ public class SysPasswordService {
String code = VerificationCodeUtils.generateVerificationCode(VerificationCodeUtils.CodeType.NUMERIC); String code = VerificationCodeUtils.generateVerificationCode(VerificationCodeUtils.CodeType.NUMERIC);
String str = "您的验证码为" + code + "尊敬的客户以上验证码3分钟有效微服务平台提醒您转发可能导致账号被盗请勿将验证码泄露于他人"; String str = "您的验证码为" + code + "尊敬的客户以上验证码3分钟有效微服务平台提醒您转发可能导致账号被盗请勿将验证码泄露于他人";
String verifyKey = CacheConstants.VERIFICATION_CODE + phone; String verifyKey = CacheConstants.VERIFICATION_CODE + phone;
String s = SmsUtils.smsToken(phone, str, ""); String s = SmsUtils.sendMsgToSms(Arrays.asList(phone), str);
if (StringUtils.isNotEmpty(s)) { if (StringUtils.isNotEmpty(s)) {
if (s.contains("ok")) { if (s.contains("ok")) {
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);

View File

@ -2,6 +2,7 @@ package com.bonus.auth.service;
import com.bonus.common.core.constant.SecurityConstants; import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R; import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.system.api.RemoteUserService; import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser; import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser; import com.bonus.system.api.model.LoginUser;
@ -33,6 +34,8 @@ public class UsernamePasswordLoginStrategy implements LoginStrategy {
*/ */
@Override @Override
public LoginUser login(String username, String password) { public LoginUser login(String username, String password) {
username = Sm4Utils.decrypt(username);
password = Sm4Utils.decrypt(password);
//参数校验 //参数校验
passwordValidatorService.validateLoginParameters(username, password); passwordValidatorService.validateLoginParameters(username, password);
// IP黑名单校验; // IP黑名单校验;

View File

@ -0,0 +1,52 @@
package com.bonus.auth.utils;
import cn.hutool.json.JSONObject;
import com.ah.sbd.SmsTool;
import com.ah.sbd.utils.param.BatchSmsByContentParam;
import com.ah.sbd.utils.param.SmsParam;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import org.springframework.util.CollectionUtils;
import java.util.List;
public class SmsUtils {
/**
* 发送消息到短信
*
* @param phoneNumbers 电话号码列表可能包含无效或重复的号码
* @param msg 要发送的短信消息内容
* @return 发送短信的结果具体形式依赖于SmsUtils.smsToken的实现
* 此方法首先检查电话号码列表是否为空如果为空则直接返回空字符串
* 接下来它会移除列表中所有为空的电话号码
* 然后对列表中超过11位的电话号码进行解密处理
* 确保只有有效的电话号码被用来发送短信
*/
public static String sendMsgToSms(List<String> phoneNumbers, String msg) {
// 检查电话号码列表和消息内容是否有效
if (CollectionUtils.isEmpty(phoneNumbers) || StringUtils.isBlank(msg)) {
return "";
}
// 过滤掉无效的电话号码
phoneNumbers.removeIf(StringUtils::isEmpty);
// 对超过11位的电话号码进行解密处理
phoneNumbers.replaceAll(phoneNumber ->
phoneNumber.length() > 11 ? Sm4Utils.decrypt(phoneNumber) : phoneNumber
);
// 根据电话号码数量发送短信
if (phoneNumbers.isEmpty()) {
return "";
} else if (phoneNumbers.size() == 1) {
JSONObject sendResult = SmsTool.sendSms(new SmsParam(phoneNumbers.get(0), msg), Constants.ANHUI_COMPANY_CANTEEN_SMS_KEY);
return sendResult.toString();
} else {
JSONObject sendResult = SmsTool.sendSms(new BatchSmsByContentParam(phoneNumbers, msg), Constants.ANHUI_COMPANY_CANTEEN_SMS_KEY);
return sendResult.toString();
}
}
}

View File

@ -5,7 +5,7 @@ spring:
name: bonus-auth name: bonus-auth
profiles: profiles:
# 环境配置 # 环境配置
active: dev active: smart_canteen_local
#加密组件 #加密组件
jasypt: jasypt:

View File

@ -138,4 +138,7 @@ public class Constants
* 指定集合的大小 * 指定集合的大小
*/ */
public static final int COMMON_COLLECTION_SIZE = 16; public static final int COMMON_COLLECTION_SIZE = 16;
// 安徽省公司短信平台-皖送e餐-key
public static final String ANHUI_COMPANY_CANTEEN_SMS_KEY = "pEw/9e5xXhKF4iVNFHUljlSTjLH5gVG+sCBHnc0Ei7w/dSjSFlw+2qRQmMmyXvJT";
} }

View File

@ -0,0 +1,69 @@
package com.bonus.common.core.utils.encryption;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
@Component
public class AesEncryptUtil {
private static final Logger log = LoggerFactory.getLogger(AesEncryptUtil.class);
private static final String KEY_ALGORITHM = "AES";
private static final String AES_ENCRYPT_KEY = "pigxpigxpigxpigx";
// @Resource
// private EncryptProperties encryptProperties;
//
// public static AesEncryptUtil getInstance() {
// return (AesEncryptUtil) SpringContextHolder.getBean(AesEncryptUtil.class);
// }
public static String aesEncrypt(String encryptStr) {
if (StrUtil.isBlank(encryptStr)) {
return encryptStr;
} else {
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(AES_ENCRYPT_KEY.getBytes(), "AES"), new IvParameterSpec(AES_ENCRYPT_KEY.getBytes()));
return aes.encryptBase64(encryptStr);
}
}
public static String aesDecode(String decodeStr) {
if (StrUtil.isBlank(decodeStr)) {
return decodeStr;
} else {
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(AES_ENCRYPT_KEY.getBytes(), "AES"), new IvParameterSpec(AES_ENCRYPT_KEY.getBytes()));
byte[] resultByte;
try {
resultByte = aes.decrypt(Base64.decode(decodeStr.getBytes(StandardCharsets.UTF_8)));
} catch (Exception var5) {
log.info("字段解密异常:" + var5.getMessage());
return decodeStr;
}
return (new String(resultByte, StandardCharsets.UTF_8)).trim();
}
}
public static void main(String[] args) {
System.out.println(aesEncrypt("Bonus$2026"));
System.out.println(aesDecode("PCAGz8j5ByU2AzoT6vtlLA=="));
System.out.println();
System.out.println(aesEncrypt("Bonus$2027"));
System.out.println(aesDecode("MF1Nui79h/OHRGoUx1jhcg=="));
System.out.println();
System.out.println(aesEncrypt("18110922397"));
System.out.println(aesDecode("poEWO1yyC/EaUR9vmrrNSA=="));
}
}

View File

@ -3,11 +3,15 @@ package com.bonus.common.core.utils.encryption;
import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.Mode; import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding; import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4; import cn.hutool.crypto.symmetric.SM4;
import lombok.extern.slf4j.Slf4j;
/** /**
* @author bonus * @author bonus
*/ */
@Slf4j
public class Sm4Utils { public class Sm4Utils {
/** /**
* 必须是16字节 * 必须是16字节
@ -15,6 +19,8 @@ public class Sm4Utils {
private static final String KEY = "78d1295afa99449b99d6f83820e6965c"; private static final String KEY = "78d1295afa99449b99d6f83820e6965c";
private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2"; private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2";
private static final String CUST_KEY = "jY7bZz6Pjml+H/WZYfNSNA==";
/** /**
* 加密数据使用固定盐 * 加密数据使用固定盐
* *
@ -33,6 +39,15 @@ public class Sm4Utils {
} }
} }
public static String custEncrypt(String data) {
try {
return SmUtil.sm4(SecureUtil.decode(CUST_KEY)).encryptBase64(data) + "##encrypted";
} catch (Exception var2) {
log.debug("SM4加密异常:{}", var2.getMessage());
return data;
}
}
/** /**
* 解密数据使用固定盐 * 解密数据使用固定盐
* *
@ -51,6 +66,20 @@ public class Sm4Utils {
} }
} }
public static String custDecrypt(String data) {
try {
if (data.endsWith("##encrypted")) {
data = data.substring(0, data.length() - "##encrypted".length());
return SmUtil.sm4(SecureUtil.decode(CUST_KEY)).decryptStr(data);
} else {
return data;
}
} catch (Exception var2) {
log.debug("SM4解密异常:{}", var2.getMessage());
return data;
}
}
// 测试方法演示加密和解密过程 // 测试方法演示加密和解密过程
public static void main(String[] args) { public static void main(String[] args) {
String plainText = "15398187429"; String plainText = "15398187429";
@ -63,5 +92,7 @@ public class Sm4Utils {
// 解密密文 // 解密密文
String decryptedText = Sm4Utils.decrypt(plainText); String decryptedText = Sm4Utils.decrypt(plainText);
System.out.println("解密后: " + decryptedText); System.out.println("解密后: " + decryptedText);
System.out.println(custEncrypt("13866134935"));
} }
} }

View File

@ -6,6 +6,7 @@ import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.utils.JwtUtils; import com.bonus.common.core.utils.JwtUtils;
import com.bonus.common.core.utils.ServletUtils; import com.bonus.common.core.utils.ServletUtils;
import com.bonus.common.core.utils.StringUtils; import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.utils.ip.IpUtils; import com.bonus.common.core.utils.ip.IpUtils;
import com.bonus.common.core.utils.uuid.IdUtils; import com.bonus.common.core.utils.uuid.IdUtils;
import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.core.web.domain.AjaxResult;
@ -65,7 +66,7 @@ public class TokenService {
*/ */
public Map<String, Object> createToken(LoginUser loginUser) { public Map<String, Object> createToken(LoginUser loginUser) {
// 检查并删除已有的token // 检查并删除已有的token
delExistingToken(loginUser.getSysUser().getUserId()); //delExistingToken(loginUser.getSysUser().getUserId());
String token = IdUtils.fastUUID(); String token = IdUtils.fastUUID();
Long userId = loginUser.getSysUser().getUserId(); Long userId = loginUser.getSysUser().getUserId();
String userName = loginUser.getSysUser().getUserName(); String userName = loginUser.getSysUser().getUserName();
@ -94,6 +95,38 @@ public class TokenService {
return rspMap; return rspMap;
} }
/**
* 创建客户令牌
*/
public Map<String, Object> createCustToken(LoginUser loginUser) {
// 检查并删除已有的token
//delExistingToken(loginUser.getCustId());
String token = IdUtils.fastUUID();
Long custId = loginUser.getCustId();
String custName = Sm4Utils.custDecrypt(loginUser.getSysUser().getCustName());
String phoneNumber = Sm4Utils.custDecrypt(loginUser.getSysUser().getPhonenumber());
loginUser.setToken(token);
loginUser.setCustId(custId);
loginUser.getSysUser().setCustName(custName);
loginUser.setIpaddr(IpUtils.getIpAddr());
loginUser.getSysUser().setPhonenumber(phoneNumber);
refreshToken(loginUser);
// Jwt存储信息
Map<String, Object> claimsMap = new HashMap<String, Object>(16);
claimsMap.put(SecurityConstants.USER_KEY, token);
claimsMap.put(SecurityConstants.DETAILS_USER_ID, custId);
claimsMap.put(SecurityConstants.DETAILS_USERNAME, phoneNumber);
String accessToken = JwtUtils.createToken(claimsMap);
Map<String, Object> rspMap = new HashMap<String, Object>(16);
rspMap.put("access_token", accessToken);
rspMap.put("expires_in", EXPIRETIME);
rspMap.put("isLogin", isLogin(String.valueOf(custId)));
long tokenTime = getTokenTime();
//对token进行存储
redisService.setCacheObject(LOGIN_USER_KEY + custId, token, tokenTime, TimeUnit.MINUTES);
return rspMap;
}
public boolean isLogin(String userId) { public boolean isLogin(String userId) {
String existingTokenKey = redisService.getCacheObject(LOGIN_USER_KEY + userId); String existingTokenKey = redisService.getCacheObject(LOGIN_USER_KEY + userId);
return existingTokenKey != null; return existingTokenKey != null;
@ -206,8 +239,12 @@ public class TokenService {
private Long getTokenTime(){ private Long getTokenTime(){
long tokenTime = 20L; long tokenTime = 20L;
String redisResult = redisService.getCacheObject("sys_config:"+ "sys.visit.tokentime"); String redisResult = redisService.getCacheObject("sys_config:"+ "sys.visit.tokentime");
if(!redisResult.isEmpty()) { if(StringUtils.isNotEmpty(redisResult)) {
tokenTime = Long.parseLong(redisResult); try {
tokenTime = Long.parseLong(redisResult);
} catch (Exception e) {
tokenTime = 43200L; //MINUTES
}
}else { }else {
Long result = systemConfig.getTokenTime(); Long result = systemConfig.getTokenTime();
if (!ObjectUtil.isEmpty(result)){ if (!ObjectUtil.isEmpty(result)){

View File

@ -0,0 +1,33 @@
package com.bonus.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Description 全局跨域配置
*/
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsWebFilter corsFilter() {
// 创建一个新的CorsConfiguration对象用于配置跨域请求
CorsConfiguration config = new CorsConfiguration();
// 允许所有的HTTP请求方法GET, POST, PUT, DELETE等
config.addAllowedMethod("*");
// 允许所有的域名发起的请求 比如http://localhost:8080
config.addAllowedOrigin("*");
// 允许所有的域名发起的请求支持正则表达式 比如http://localhost:8080
config.addAllowedOriginPattern("*");
// 允许所有的请求头部信息 比如tokenContent-Type
config.addAllowedHeader("*");
// 创建一个UrlBasedCorsConfigurationSource对象并使用PathPatternParser进行路径匹配
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
// 注册跨域配置应用于所有的URL路径
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}

View File

@ -5,7 +5,7 @@ spring:
name: bonus-gateway name: bonus-gateway
profiles: profiles:
# 环境配置 # 环境配置
active: dev active: smart_canteen_local
#加密组件 #加密组件
jasypt: jasypt:

View File

@ -6,7 +6,7 @@ spring:
profiles: profiles:
# 环境配置 # 环境配置
active: dev active: smart_canteen_local
#加密组件 #加密组件
jasypt: jasypt:

View File

@ -81,7 +81,25 @@ public class SysUserController extends BaseController {
@SysLog(title = "用户管理", businessType = OperaType.QUERY, logType = 0, module = "系统管理->用户管理", details = "查询用户列表") @SysLog(title = "用户管理", businessType = OperaType.QUERY, logType = 0, module = "系统管理->用户管理", details = "查询用户列表")
public TableDataInfo list(SysUser user) { public TableDataInfo list(SysUser user) {
try { try {
startPage(); if (user.isPagination()) {
startPage();
}
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
} catch (Exception e) {
logger.error(e.toString(), e);
}
return getDataTableError(new ArrayList<>());
}
//@RequiresPermissionsOrInnerAuth(innerAuth = @InnerAuth(isUser = false), requiresPermissions = @RequiresPermissions("system:user:list"))
@PostMapping("/listByPost")
@SysLog(title = "用户管理", businessType = OperaType.QUERY, logType = 0, module = "系统管理->用户管理", details = "查询用户列表")
public TableDataInfo listByPost(@RequestBody SysUser user) {
try {
if (user.isPagination()) {
startPage();
}
List<SysUser> list = userService.selectUserList(user); List<SysUser> list = userService.selectUserList(user);
return getDataTable(list); return getDataTable(list);
} catch (Exception e) { } catch (Exception e) {
@ -206,6 +224,32 @@ public class SysUserController extends BaseController {
return R.ok(sysUserVo); return R.ok(sysUserVo);
} }
/**
* 获取当前用户信息
*/
@InnerAuth
@GetMapping("/custInfoPhoto/{photoNumber}")
public R<LoginUser> custInfoPhotoNumber(@PathVariable("photoNumber") String photoNumber) {
SysUser sysUser = userService.selectCustInfoByPhoneNumber(photoNumber);
if (StringUtils.isNull(sysUser)) {
return R.fail("用户名或密码错误");
}
// SysDept sysDept = deptService.selectActiveDeptById(sysUser.getCompanyId());
// if (StringUtils.isNull(sysDept)) {
// return R.fail("用户所在公司停用或注销");
// }
// 角色集合
//Set<String> roles = permissionService.getRolePermission(sysUser);
// 权限集合
//Set<String> permissions = permissionService.getMenuPermission(sysUser);
LoginUser loginUser = new LoginUser();
loginUser.setCustId(sysUser.getCustId());
loginUser.setSysUser(sysUser);
//sysUserVo.setRoles(roles);
//sysUserVo.setPermissions(permissions);
return R.ok(loginUser);
}
/** /**
* 注册用户信息 * 注册用户信息
*/ */
@ -465,7 +509,7 @@ public class SysUserController extends BaseController {
/** /**
* 获取部门树列表 * 获取部门树列表
*/ */
@RequiresPermissionsOrInnerAuth(innerAuth = @InnerAuth, requiresPermissions = @RequiresPermissions("system:user:list")) //@RequiresPermissionsOrInnerAuth(innerAuth = @InnerAuth, requiresPermissions = @RequiresPermissions("system:user:list"))
@GetMapping("/deptTree") @GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept) { public AjaxResult deptTree(SysDept dept) {
try { try {
@ -476,10 +520,20 @@ public class SysUserController extends BaseController {
return error("系统异常,请联系管理员"); return error("系统异常,请联系管理员");
} }
@PostMapping("/deptTreeByPost")
public AjaxResult deptTreeByPost(SysDept dept) {
try {
return success(deptService.selectDeptTreeList(dept));
} catch (Exception e) {
logger.error(e.toString(), e);
}
return error("系统异常,请联系管理员");
}
/** /**
* 查询部门人员树列表 * 查询部门人员树列表
*/ */
@RequiresPermissionsOrInnerAuth(innerAuth = @InnerAuth, requiresPermissions = @RequiresPermissions("system:user:list")) //@RequiresPermissionsOrInnerAuth(innerAuth = @InnerAuth, requiresPermissions = @RequiresPermissions("system:user:list"))
@PostMapping("/deptUserTree") @PostMapping("/deptUserTree")
public AjaxResult deptUserTree(@RequestBody SysUser sysUser) { public AjaxResult deptUserTree(@RequestBody SysUser sysUser) {
try { try {

View File

@ -25,6 +25,8 @@ public class TreeSelect implements Serializable {
/** 父部门ID */ /** 父部门ID */
private Long parentId; private Long parentId;
private Long nodeId;
/** /**
* 节点名称 * 节点名称
*/ */
@ -48,6 +50,7 @@ public class TreeSelect implements Serializable {
public TreeSelect(SysDept dept) { public TreeSelect(SysDept dept) {
this.id = dept.getDeptId(); this.id = dept.getDeptId();
this.parentId = dept.getParentId(); this.parentId = dept.getParentId();
this.nodeId = dept.getNodeId();
this.status = dept.getStatus(); this.status = dept.getStatus();
this.label = dept.getDeptName(); this.label = dept.getDeptName();
this.level = dept.getLevel(); this.level = dept.getLevel();
@ -85,6 +88,14 @@ public class TreeSelect implements Serializable {
this.parentId = parentId; this.parentId = parentId;
} }
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public String getLabel() { public String getLabel() {
return label; return label;
} }

View File

@ -155,4 +155,13 @@ public interface SysUserMapper {
Integer approvalStatus(Long userId); Integer approvalStatus(Long userId);
int systemUpdateUser(SysUser user); int systemUpdateUser(SysUser user);
/**
* 通过手机号查询用户
*
* @param phoneNumber 手机号
* @return 用户对象信息
*/
public SysUser selectCustInfoByPhoneNumber(@Param("phoneNumber") String phoneNumber);
} }

View File

@ -237,5 +237,5 @@ public interface ISysUserService {
public AjaxResult systemUpdateUser(SysUser user); public AjaxResult systemUpdateUser(SysUser user);
public SysUser selectCustInfoByPhoneNumber(String photoNumber);
} }

View File

@ -15,10 +15,7 @@ import com.bonus.common.datascope.annotation.DataScope;
import com.bonus.common.datascope.utils.CommonDataPermissionInfo; import com.bonus.common.datascope.utils.CommonDataPermissionInfo;
import com.bonus.common.security.config.VerificationCodeConfig; import com.bonus.common.security.config.VerificationCodeConfig;
import com.bonus.common.security.utils.SecurityUtils; import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.domain.SysPost; import com.bonus.system.api.domain.*;
import com.bonus.system.api.domain.SysRole;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.domain.SysUserRole;
import com.bonus.system.domain.SysUserPost; import com.bonus.system.domain.SysUserPost;
import com.bonus.system.mapper.*; import com.bonus.system.mapper.*;
import com.bonus.system.service.ISysConfigService; import com.bonus.system.service.ISysConfigService;
@ -109,7 +106,7 @@ public class SysUserServiceImpl implements ISysUserService {
String phone =user.getPhonenumber().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_"); String phone =user.getPhonenumber().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
user.setPhonenumber(phone); user.setPhonenumber(phone);
} }
user.setCompanyId(SecurityUtils.getLoginUser().getSysUser().getCompanyId()); //user.setCompanyId(SecurityUtils.getLoginUser().getSysUser().getCompanyId());
List<SysUser> sysUsers = userMapper.selectUserList(user); List<SysUser> sysUsers = userMapper.selectUserList(user);
return sysUsers; return sysUsers;
} }
@ -602,9 +599,9 @@ public class SysUserServiceImpl implements ISysUserService {
} }
Integer i = userMapper.approvalStatus(userId); Integer i = userMapper.approvalStatus(userId);
if (i > 0) { if (i > 0) {
if (StringUtils.isNotEmpty(sysUser.getPhonenumber())) { // if (StringUtils.isNotEmpty(sysUser.getPhonenumber())) {
SmsUtils.smsToken(sysUser.getPhonenumber(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统", ""); // SmsUtils.smsToken(sysUser.getPhonenumber(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统", "");
} // }
if (StringUtils.isNotEmpty(sysUser.getEmail())) { if (StringUtils.isNotEmpty(sysUser.getEmail())) {
sendSimpleEmail(sysUser.getEmail(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统"); sendSimpleEmail(sysUser.getEmail(), "您的账号:" + sysUser.getUserName() + "已通过审批,请登录系统");
} }
@ -649,4 +646,15 @@ public class SysUserServiceImpl implements ISysUserService {
return R.ok(); return R.ok();
} }
/**
* 通过用户名查询用户
*
* @param photoNumber 用户名
* @return 用户对象信息
*/
@Override
public SysUser selectCustInfoByPhoneNumber(String photoNumber) {
return userMapper.selectCustInfoByPhoneNumber(Sm4Utils.custEncrypt(photoNumber));
}
} }

View File

@ -5,7 +5,7 @@ spring:
name: bonus-system name: bonus-system
profiles: profiles:
# 环境配置 # 环境配置
active: dev active: smart_canteen_local
task: task:
scheduling: scheduling:
pool: pool:

View File

@ -112,9 +112,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT SELECT
d.dept_id AS deptId, d.dept_id AS deptId,
d.parent_id AS parentId, d.parent_id AS parentId,
d.dept_id as nodeId,
d.dept_name AS deptName, d.dept_name AS deptName,
LENGTH( d.ancestors ) - LENGTH( LENGTH( d.ancestors ) - LENGTH(
REPLACE ( d.ancestors, ',', '' )) AS LEVEL REPLACE ( d.ancestors, ',', '' )) AS level
FROM FROM
sys_dept d sys_dept d
WHERE WHERE
@ -124,10 +125,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
UNION UNION
SELECT SELECT
su.user_id AS deptId, CONCAT(sd.dept_id,'9999',su.user_id) AS deptId,
sd.dept_id AS parentId, sd.dept_id AS parentId,
su.user_id as nodeId,
su.nick_name AS deptName, su.nick_name AS deptName,
99 AS LEVEL 99 AS level
FROM FROM
sys_user su sys_user su
LEFT JOIN sys_user_role sr ON su.user_id = sr.user_id LEFT JOIN sys_user_role sr ON su.user_id = sr.user_id

View File

@ -144,6 +144,24 @@
#{item} #{item}
</foreach> </foreach>
</if> </if>
<if test="roles != null and roles.size() > 0">
and r.role_key in
<foreach collection="roles" item="item" index="index" separator="," open="(" close=")">
#{item.roleKey}
</foreach>
</if>
<if test="userIds != null and userIds.length > 0">
and u.user_id in
<foreach collection="userIds" item="item" index="index" separator="," open="(" close=")">
#{item}
</foreach>
</if>
<if test="userNames != null and userNames.length > 0">
and u.user_name in
<foreach collection="userNames" item="item" index="index" separator="," open="(" close=")">
#{item}
</foreach>
</if>
<include refid="com.bonus.system.mapper.DataScopeMapper.dataScopeFilter"/> <include refid="com.bonus.system.mapper.DataScopeMapper.dataScopeFilter"/>
GROUP BY u.user_id GROUP BY u.user_id
</select> </select>
@ -369,5 +387,17 @@
</foreach> </foreach>
</delete> </delete>
<!--根据人员id集合获取人员信息-->
<select id="selectCustInfoByPhoneNumber" resultType="com.bonus.system.api.domain.SysUser">
select cust_id as custId, cust_name as custName, cust_num as custNum, cust_photo_url as custPhotoUrl,
mobile as phonenumber, pwd as password
from cust_info
<where>
cust_state = 1 and (psn_type != 999 or psn_type is null)
<if test="phoneNumber != null and phoneNumber != ''">
and mobile = #{phoneNumber}
</if>
</where>
</select>
</mapper> </mapper>