Merge remote-tracking branch 'origin/jtdev' into jtdev
18 files modified
3 files added
1 files deleted
| New file |
| | |
| | | package cn.gistack.auth.config; |
| | | |
| | | import cn.gistack.auth.utils.TokenUtil; |
| | | import cn.gistack.common.cache.CacheNames; |
| | | import com.alibaba.nacos.common.utils.StringUtils; |
| | | import lombok.SneakyThrows; |
| | | import org.springblade.core.redis.cache.BladeRedis; |
| | | import org.springblade.core.tool.utils.DigestUtil; |
| | | import org.springblade.core.tool.utils.Func; |
| | | import org.springblade.core.tool.utils.WebUtil; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.authentication.BadCredentialsException; |
| | | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| | | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; |
| | | import org.springframework.security.core.AuthenticationException; |
| | | import org.springframework.security.core.userdetails.UserDetails; |
| | | 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.Component; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.time.Duration; |
| | | |
| | | /** |
| | | * 自定义安全认证 |
| | | * @author zhongrj |
| | | * @time 2022-9-2 |
| | | */ |
| | | @Component |
| | | public class MyAuthenticationProvider extends DaoAuthenticationProvider { |
| | | |
| | | /** |
| | | * 免密常量 |
| | | */ |
| | | public static final String CUSTOM_LOGIN_SMS = "CUSTOM_LOGIN_SMS"; |
| | | |
| | | @Autowired |
| | | private BladeRedis bladeRedis; |
| | | |
| | | /** |
| | | * 设置 userDetailsService |
| | | * @param userDetailsService |
| | | */ |
| | | public MyAuthenticationProvider(UserDetailsService userDetailsService) { |
| | | super(); |
| | | setUserDetailsService(userDetailsService); |
| | | } |
| | | |
| | | /** |
| | | * 自定义处理密码校验逻辑 |
| | | * @param userDetails 用户信息 |
| | | * @param authentication 认证对象信息 |
| | | * @throws AuthenticationException 认证异常对象信息 |
| | | */ |
| | | @SneakyThrows |
| | | @Override |
| | | protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { |
| | | if (authentication.getCredentials() == null) { |
| | | this.logger.debug("Authentication failed: no credentials provided"); |
| | | throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); |
| | | } else { |
| | | String password = authentication.getCredentials().toString(); |
| | | // 手机号登录时不验证密码 |
| | | if(!CUSTOM_LOGIN_SMS.equals(password)){ |
| | | HttpServletRequest request = WebUtil.getRequest(); |
| | | String grantType = request.getParameter(TokenUtil.GRANT_TYPE_KEY); |
| | | // 获取租户ID |
| | | String headerTenant = request.getHeader(TokenUtil.TENANT_HEADER_KEY); |
| | | String paramTenant = request.getParameter(TokenUtil.TENANT_PARAM_KEY); |
| | | // 指定租户ID |
| | | String tenantId = StringUtils.isBlank(headerTenant) ? paramTenant : headerTenant; |
| | | String detailsPassword = userDetails.getPassword().substring(7); |
| | | if (!detailsPassword.equals(DigestUtil.hex(password))) { |
| | | int count = getFailCount(tenantId, userDetails.getUsername()); |
| | | // 用户存在但密码错误,超过次数则锁定账号 |
| | | if (grantType != null && !grantType.equals(TokenUtil.REFRESH_TOKEN_KEY)) { |
| | | setFailCount(tenantId, userDetails.getUsername(), count); |
| | | throw new UserDeniedAuthorizationException(TokenUtil.USER_NOT_FOUND); |
| | | } |
| | | this.logger.debug("Failed to authenticate since password does not match stored value"); |
| | | throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); |
| | | } |
| | | // 成功则清除登录错误次数 |
| | | delFailCount(tenantId, userDetails.getUsername()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取账号错误次数 |
| | | * |
| | | * @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)); |
| | | } |
| | | } |
| | |
| | | import cn.gistack.auth.support.BladePasswordEncoderFactories; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.SneakyThrows; |
| | | 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.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.annotation.web.builders.WebSecurity; |
| | | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
| | |
| | | @AllArgsConstructor |
| | | public class SecurityConfiguration extends WebSecurityConfigurerAdapter { |
| | | |
| | | @Autowired |
| | | private MyAuthenticationProvider myAuthenticationProvider; |
| | | |
| | | /** |
| | | * 认证设置 |
| | | * @param auth 认证manager |
| | | * @throws Exception 异常 |
| | | */ |
| | | @Override |
| | | protected void configure(AuthenticationManagerBuilder auth) throws Exception { |
| | | //设置自定义认证provider |
| | | auth.authenticationProvider(myAuthenticationProvider); |
| | | } |
| | | |
| | | @Bean |
| | | @Override |
| | | @SneakyThrows |
| | |
| | | List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter())); |
| | | // 增加验证码模式 |
| | | granters.add(new CaptchaTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), bladeRedis)); |
| | | // 增加手机验证码模式 |
| | | granters.add(new PhoneTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), bladeRedis)); |
| | | // 增加第三方登陆模式 |
| | | granters.add(new SocialTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), userClient, socialProperties)); |
| | | // 组合tokenGranter集合 |
| New file |
| | |
| | | package cn.gistack.auth.granter; |
| | | |
| | | import cn.gistack.auth.utils.TokenUtil; |
| | | import cn.gistack.common.cache.CacheNames; |
| | | import org.springblade.core.redis.cache.BladeRedis; |
| | | import org.springblade.core.tool.utils.StringUtil; |
| | | import org.springframework.security.authentication.*; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; |
| | | import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException; |
| | | import org.springframework.security.oauth2.provider.*; |
| | | import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; |
| | | import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 验证码TokenGranter |
| | | * |
| | | * @author Chill |
| | | */ |
| | | public class PhoneTokenGranter extends AbstractTokenGranter { |
| | | |
| | | private static final String GRANT_TYPE = "phone"; |
| | | |
| | | private final AuthenticationManager authenticationManager; |
| | | |
| | | private BladeRedis bladeRedis; |
| | | |
| | | public PhoneTokenGranter(AuthenticationManager authenticationManager, |
| | | AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, BladeRedis bladeRedis) { |
| | | this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); |
| | | this.bladeRedis = bladeRedis; |
| | | } |
| | | |
| | | protected PhoneTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, |
| | | ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) { |
| | | super(tokenServices, clientDetailsService, requestFactory, grantType); |
| | | this.authenticationManager = authenticationManager; |
| | | } |
| | | |
| | | @Override |
| | | protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { |
| | | Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters()); |
| | | String phone = parameters.get("username"); |
| | | String code = parameters.get("password"); |
| | | // 获取验证码 |
| | | String redisCode = bladeRedis.get(CacheNames.PHONE_KEY + phone); |
| | | // 判断验证码 |
| | | if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) { |
| | | throw new UserDeniedAuthorizationException(TokenUtil.CAPTCHA_NOT_CORRECT); |
| | | } |
| | | // 通过手机号查询用户 |
| | | Authentication userAuth = new UsernamePasswordAuthenticationToken(phone, "CUSTOM_LOGIN_SMS"); |
| | | ((AbstractAuthenticationToken) userAuth).setDetails(parameters); |
| | | try { |
| | | userAuth = authenticationManager.authenticate(userAuth); |
| | | } |
| | | catch (AccountStatusException | BadCredentialsException ase) { |
| | | //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) |
| | | throw new InvalidGrantException(ase.getMessage()); |
| | | } |
| | | // If the username/password are wrong the spec says we should send 400/invalid grant |
| | | |
| | | if (userAuth == null || !userAuth.isAuthenticated()) { |
| | | throw new InvalidGrantException("Could not authenticate user: " + phone); |
| | | } |
| | | |
| | | OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); |
| | | return new OAuth2Authentication(storedOAuth2Request, userAuth); |
| | | } |
| | | } |
| | |
| | | import cn.gistack.sm.sjztmd.entity.AttResManagePerson; |
| | | import cn.gistack.sm.sjztmd.feign.IAttResManagePersonClient; |
| | | import cn.gistack.system.entity.Dept; |
| | | import cn.gistack.system.entity.Role; |
| | | import com.alibaba.nacos.common.utils.StringUtils; |
| | | import io.jsonwebtoken.Claims; |
| | | import lombok.AllArgsConstructor; |
| | |
| | | // 获取租户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)) { |
| | |
| | | // 用户不存在,但提示用户名与密码错误并锁定账号 |
| | | 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); |
| | | throw new UserDeniedAuthorizationException(TokenUtil.USER_NOT_FOUND); |
| | | } |
| | | // 用户角色不存在 |
| | | if (Func.isEmpty(userInfo.getRoles())) { |
| | |
| | | R<Dept> deptRes = sysClient.getDept(Long.valueOf(deptStr)); |
| | | if (StringUtil.isBlank(deptRes.getData().getAdCode())) |
| | | // 部门为空 |
| | | throw new UsernameNotFoundException("没有找到有效组织机构~"); |
| | | throw new UserDeniedAuthorizationException("没有找到有效组织机构~"); |
| | | else |
| | | userInfo.getDetail().set("adCodeBase",attResManagePersonClient.getAdBaseById(deptRes.getData().getAdCode()).getData()); |
| | | |
| | | // 成功则清除登录错误次数 |
| | | 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, |
| | |
| | | |
| | | import org.springblade.core.tool.utils.DigestUtil; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 自定义密码加密 |
| | | * |
| | | * @author Chill |
| | | */ |
| | | @Component |
| | | public class BladePasswordEncoder implements PasswordEncoder { |
| | | |
| | | @Override |
| | |
| | | |
| | | public final static String DEPT_HEADER_KEY = "Dept-Id"; |
| | | public final static String ROLE_HEADER_KEY = "Role-Id"; |
| | | public final static String PHONE_HEADER_KEY = "Phone-Key"; |
| | | public final static String PHONE_HEADER_CODE = "Phone-Code"; |
| | | public final static String CAPTCHA_HEADER_KEY = "Captcha-Key"; |
| | | public final static String CAPTCHA_HEADER_CODE = "Captcha-Code"; |
| | | public final static String CAPTCHA_NOT_CORRECT = "验证码不正确"; |
| | |
| | | String CAPTCHA_KEY = "blade:auth::blade:captcha:"; |
| | | |
| | | /** |
| | | * 手机验证码key |
| | | */ |
| | | String PHONE_KEY = "blade:auth::blade:phone:"; |
| | | |
| | | /** |
| | | * 登录失败key |
| | | */ |
| | | String USER_FAIL_KEY = "blade:user::blade:fail:"; |
| | |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * User Feign接口类 |
| | | * |
| | |
| | | String USER_INFO_BY_TYPE = API_PREFIX + "/user-info-by-type"; |
| | | String USER_INFO_BY_ID = API_PREFIX + "/user-info-by-id"; |
| | | String USER_INFO_BY_ACCOUNT = API_PREFIX + "/user-info-by-account"; |
| | | String USER_INFO_BY_PHONE = API_PREFIX + "/user-info-by-phone"; |
| | | String USER_INFO_BY_PHONE_OR_ACCOUNT = API_PREFIX + "/user-info-by-phone-or-account"; |
| | | String USER_AUTH_INFO = API_PREFIX + "/user-auth-info"; |
| | | String SAVE_USER = API_PREFIX + "/save-user"; |
| | | String REMOVE_USER = API_PREFIX + "/remove-user"; |
| | |
| | | * 获取用户信息 |
| | | * |
| | | * @param tenantId 租户ID |
| | | * @param phone 手机号 |
| | | * @return |
| | | */ |
| | | @GetMapping(USER_INFO_BY_PHONE) |
| | | R<List<User>> userInfoByPhone(@RequestParam("tenantId") String tenantId, @RequestParam("phone") String phone); |
| | | |
| | | /** |
| | | * 获取用户信息 |
| | | * |
| | | * @param tenantId 租户ID |
| | | * @param phone 手机号或者账户 |
| | | * @return |
| | | */ |
| | | @GetMapping(USER_INFO_BY_PHONE_OR_ACCOUNT) |
| | | R<List<User>> userInfoByPhoneOrAccount(@RequestParam("tenantId") String tenantId, @RequestParam("phone") String phone); |
| | | |
| | | /** |
| | | * 获取用户信息 |
| | | * |
| | | * @param tenantId 租户ID |
| | | * @param account 账号 |
| | | * @param userType 用户平台 |
| | | * @return |
| | |
| | | <version>3.0.1.RELEASE</version> |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>cn.gistack</groupId> |
| | | <artifactId>skjcmanager-user-api</artifactId> |
| | | <version>3.0.1.RELEASE</version> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springblade.core.tool.api.R; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | |
| | | * 创建任务 |
| | | * @return |
| | | */ |
| | | @GetMapping("/createCall") |
| | | public R createCall(){ |
| | | List<Map<String,String>> list = new ArrayList<>(); |
| | | Map<String,String> maps = new HashMap<>(); |
| | | maps.put("phone","15170720695"); |
| | | maps.put("name","测试水库"); |
| | | maps.put("over","1.2"); |
| | | maps.put("code","1241241122"); |
| | | maps.put("userName","zrj"); |
| | | maps.put("userId","123456"); |
| | | list.add(maps); |
| | | callService.createTask(list); |
| | | @PostMapping("/createCall") |
| | | public R createCall(@RequestBody List<Map<String,String>> list){ |
| | | // 返回 |
| | | return R.status(true); |
| | | return R.data(callService.createTask(list)); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | public interface CallService { |
| | | |
| | | void createTask(List<Map<String, String>> params); |
| | | /** |
| | | * 创建任务 |
| | | * @param params |
| | | * @return |
| | | */ |
| | | Object createTask(List<Map<String, String>> params); |
| | | |
| | | /** |
| | | * 获取通话详情 |
| | | * @param taskId |
| | | * @param calleeNumber |
| | | * @return |
| | | */ |
| | | Object getCallDetail(String taskId, String calleeNumber); |
| | | } |
| | |
| | | private final static String CREATE_TASK_URL = "/api/task/createTask.json"; |
| | | private final static String CALL_DETAIL_URL = "/api/task/callDetail.json"; |
| | | |
| | | /** |
| | | * 创建任务 |
| | | * @param params |
| | | * @return |
| | | */ |
| | | @Override |
| | | public void createTask(List<Map<String, String>> params) { |
| | | public Object createTask(List<Map<String, String>> params) { |
| | | String requestUrl = url + CREATE_TASK_URL; |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | String timestamp = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS")); |
| | |
| | | if (response.getStatusCode() != HttpStatus.OK) { |
| | | log.error("创建智能外呼任务失败:{}", response.getStatusCode()); |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取通话详情 |
| | | * @param taskId |
| | | * @param calleeNumber |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Object getCallDetail(String taskId, String calleeNumber) { |
| | | String requestUrl = url + CALL_DETAIL_URL; |
| | |
| | | import cn.com.flaginfo.sdk.cmc.api.sms.dynsend.DynSMSSendRequest; |
| | | import cn.com.flaginfo.sdk.cmc.api.sms.send.SMSSendRequest; |
| | | import cn.gistack.sm.sms.entity.SmsRecord; |
| | | import cn.gistack.sm.sms.entity.SmsRequest; |
| | | import cn.gistack.sm.sms.service.ISmsRecordService; |
| | | import cn.gistack.sm.sms.util.SmsUtils; |
| | | import cn.gistack.system.user.entity.User; |
| | | import cn.gistack.system.user.feign.IUserClient; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springblade.core.redis.cache.BladeRedis; |
| | | import org.springblade.core.tool.api.R; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | import static cn.gistack.common.cache.CacheNames.PHONE_KEY; |
| | | |
| | | /** |
| | | * 短信发送控制层 |
| | |
| | | |
| | | private final ISmsRecordService smsRecordService; |
| | | |
| | | |
| | | private final BladeRedis bladeRedis; |
| | | |
| | | private final IUserClient userClient; |
| | | |
| | | @GetMapping("/test") |
| | | public void setRedis(){ |
| | | saveCodeForRedis("super_admin","123456"); |
| | | } |
| | | |
| | | /** |
| | | * 发送登录验证码 |
| | | * request 必须包含手机号(多个手机号以英文逗号分隔) |
| | | * request 必须包含手机号 |
| | | * @param request |
| | | * @return |
| | | */ |
| | | @PostMapping("/sendCode") |
| | | public R test(@RequestBody SMSSendRequest request){ |
| | | //设置模板相关信息 |
| | | String templateId = "2431012205498"; |
| | | String randNumber = SmsUtils.getRandNumber(); |
| | | String content = "您的登录验证码是" + randNumber + ",5分钟内有效,请勿泄漏,如非本人操作,请忽略此信息"; |
| | | request.setMessageContent(content); |
| | | request.setTemplateId(templateId); |
| | | // 发送操作 |
| | | String sendMsg = SmsUtils.sendMsg(request); |
| | | // 记录发送记录操作 |
| | | saveSendRecord(request,sendMsg); |
| | | // 保存验证码到 redis |
| | | saveCodeForRedis(request.getUserNumber(),randNumber); |
| | | // 手机号码校验 |
| | | if(validatePhone(request.getUserNumber())) { |
| | | //设置模板相关信息 |
| | | String templateId = "2431012205498"; |
| | | String randNumber = SmsUtils.getRandNumber(); |
| | | String content = "您的登录验证码是" + randNumber + ",5分钟内有效,请勿泄漏,如非本人操作,请忽略此信息"; |
| | | request.setMessageContent(content); |
| | | request.setTemplateId(templateId); |
| | | // 发送操作 |
| | | String sendMsg = SmsUtils.sendMsg(request); |
| | | JSONObject jsonObject = JSON.parseObject(sendMsg); |
| | | // 记录发送记录操作 |
| | | saveSendRecord(request, sendMsg); |
| | | // 保存验证码到 redis |
| | | saveCodeForRedis(request.getUserNumber(), randNumber); |
| | | // 返回发送信息 |
| | | return R.data(jsonObject); |
| | | } |
| | | // 返回发送信息 |
| | | return R.data(sendMsg); |
| | | return R.fail(400,"该手机号不存在!"); |
| | | } |
| | | |
| | | /** |
| | | * 校验手机号码正确性 |
| | | * @param userNumber |
| | | * @return |
| | | */ |
| | | private boolean validatePhone(String userNumber) { |
| | | // 校验手机号码正确性 |
| | | if (validator(userNumber)){ |
| | | // 校验该账户是否已注册,通过手机号查询用户是否存在,tenantId 暂时写死,未登陆情况 tenantId 获取不到 |
| | | R<List<User>> list = userClient.userInfoByPhoneOrAccount("000000", userNumber); |
| | | if (list.getData().size()>0){ |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 校验手机号码 |
| | | */ |
| | | public static boolean validator(String phone) { |
| | | String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$"; |
| | | if (phone.length() != 11) { |
| | | return false; |
| | | } else { |
| | | Pattern p = Pattern.compile(regex); |
| | | Matcher m = p.matcher(phone); |
| | | boolean isMatch = m.matches(); |
| | | return isMatch; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param randNumber |
| | | */ |
| | | private void saveCodeForRedis(String userNumber, String randNumber) { |
| | | bladeRedis.setEx(userNumber,randNumber,5*60L); |
| | | bladeRedis.setEx(PHONE_KEY + userNumber,randNumber,5*60L); |
| | | } |
| | | |
| | | /** |
| | |
| | | smsRecordService.save(smsRecord); |
| | | } |
| | | |
| | | @PostMapping("/test1") |
| | | public R test1(@RequestBody DynSMSSendRequest request){ |
| | | return R.data(SmsUtils.dynSendMethod(request)); |
| | | /** |
| | | * 发送邮件提醒 |
| | | * @param request |
| | | * @return |
| | | */ |
| | | @PostMapping("/sendEmailMsg") |
| | | public R sendEmailMsg(@RequestBody SmsRequest request){ |
| | | // 处理数据(可能是多个手机号情况) |
| | | List<String> list = Arrays.asList(request.getPhone().split(",")); |
| | | // 遍历 |
| | | for (String phone : list) { |
| | | DynSMSSendRequest dynSMSSendRequest = new DynSMSSendRequest(); |
| | | dynSMSSendRequest.setTemplateId("2431012165350"); |
| | | dynSMSSendRequest.setDynData(new String[][]{{"手机号码","标题"},{phone,request.getContent()}}); |
| | | // 发送邮件短信 |
| | | SmsUtils.dynSendMethod(dynSMSSendRequest); |
| | | } |
| | | return R.status(true); |
| | | } |
| | | } |
| New file |
| | |
| | | package cn.gistack.sm.sms.entity; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author zhongrj |
| | | * @date 2023-04-25 |
| | | */ |
| | | @Data |
| | | public class SmsRequest { |
| | | |
| | | /** |
| | | * 手机号 |
| | | */ |
| | | private String phone; |
| | | |
| | | /** |
| | | * 内容 |
| | | */ |
| | | private String content; |
| | | } |
| | |
| | | import cn.gistack.sm.sms.constant.SmsConstant; |
| | | import com.alibaba.fastjson.JSON; |
| | | import org.aspectj.lang.annotation.Before; |
| | | import org.springblade.core.redis.cache.BladeRedis; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | |
| | | import java.util.List; |
| | | import java.util.Random; |
| | | |
| | | import static cn.gistack.common.cache.CacheNames.PHONE_KEY; |
| | | import static cn.gistack.sm.sms.constant.SmsConstant.*; |
| | | |
| | | @Component |
| | | public class SmsUtils { |
| | | |
| | | @Autowired |
| | | private BladeRedis bladeRedis; |
| | | |
| | | /** |
| | | * 固定内容发送 |
| | |
| | | return JSON.toJSONString(request); |
| | | } |
| | | |
| | | // public static void main(String[] args) { |
| | | // SMSSendRequest sendRequest = new SMSSendRequest(); |
| | | // sendRequest.setMessageContent("你有一项编号为12349的事务需要处理;"); |
| | | // sendRequest.setTemplateId("2431012234034"); |
| | | // sendRequest.setUserNumber("15170720695"); |
| | | // String s = sendMsg(sendRequest); |
| | | // System.out.println("s = " + s); |
| | | // } |
| | | |
| | | /** |
| | | * 获取随机字符串 |
| | | * @return |
| | | */ |
| | | public static String getRandNumber() { |
| | | // 计算token |
| | | // Date date = new Date(); |
| | | // String dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(date); |
| | | Random random = new Random(); |
| | | //把随机生成的数字转成字符串 |
| | | String str = String.valueOf(random.nextInt(9)); |
| | | for (int i = 0; i < 5; i++) { |
| | | str += random.nextInt(9); |
| | | } |
| | | return String.valueOf(System.currentTimeMillis()) + str; |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | |
| | | DynSMSAPI api = (DynSMSAPI) provider.getApi(ApiEnum.SENDDYNSMS); |
| | | api.setRequestUrl(SmsConstant.HOST + SmsConstant.sendVarUrl); |
| | | //请求参数 |
| | | // sendRequest.setDynData(new String[][]{{"手机号码", "编号"}, {"13000000000", "456"}}); |
| | | sendRequest.setSerialNumber(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())); |
| | | ComResult<DynSMSSendDataResult> result = api.request(sendRequest); |
| | | return JSON.toJSONString(result); |
| | |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 用户服务Feign实现类 |
| | | * |
| | |
| | | } |
| | | |
| | | @Override |
| | | @GetMapping(USER_INFO_BY_PHONE) |
| | | public R<List<User>> userInfoByPhone(String tenantId, String phone) { |
| | | return R.data(service.userInfoByPhone(tenantId, phone)); |
| | | } |
| | | |
| | | @Override |
| | | @GetMapping(USER_INFO_BY_PHONE_OR_ACCOUNT) |
| | | public R<List<User>> userInfoByPhoneOrAccount(String tenantId, String phone) { |
| | | return R.data(service.userInfoByPhoneOrAccount(tenantId, phone)); |
| | | } |
| | | |
| | | @Override |
| | | @GetMapping(USER_INFO_BY_TYPE) |
| | | public R<UserInfo> userInfo(String tenantId, String account, String userType) { |
| | | return R.data(service.userInfo(tenantId, account, UserEnum.of(userType))); |
| | |
| | | List<UserExcel> exportUser(@Param("ew") Wrapper<User> queryWrapper); |
| | | |
| | | List<User> customizeGetList(@Param("user") UserVO user); |
| | | |
| | | /** |
| | | * 根据手机号码或者账户查询用户信息 |
| | | * @param tenantId 租户id |
| | | * @param key 账户或者手机号 |
| | | * @return |
| | | */ |
| | | List<User> selectUserByPhoneOrAccount(@Param("tenantId")String tenantId, @Param("key")String key); |
| | | } |
| | |
| | | where D.AD_CODE = #{user.adCode} and U.ROLE_ID like CONCAT('%',(select id from BLADE_ROLE where ROLE_ALIAS = 'qxgly'),'%') |
| | | </select> |
| | | |
| | | <!--根据手机号码或者账户查询用户信息--> |
| | | <select id="selectUserByPhoneOrAccount" resultType="cn.gistack.system.user.entity.User"> |
| | | select * from BLADE_USER where is_deleted = 0 |
| | | and TENANT_ID = #{tenantId} |
| | | and (ACCOUNT = #{key} or PHONE = #{key}) |
| | | </select> |
| | | |
| | | </mapper> |
| | |
| | | UserVO platformDetail(User user); |
| | | |
| | | List<User> customizeGetList(UserVO user); |
| | | |
| | | /** |
| | | * 根据手机号码查询用户信息 |
| | | * @param tenantId |
| | | * @param phone |
| | | * @return |
| | | */ |
| | | List<User> userInfoByPhone(String tenantId, String phone); |
| | | |
| | | /** |
| | | * 根据手机号码或者账户查询用户信息 |
| | | * @param tenantId 租户id |
| | | * @param key 账户或者手机号 |
| | | * @return |
| | | */ |
| | | List<User> userInfoByPhoneOrAccount(String tenantId, String key); |
| | | } |
| | |
| | | |
| | | @Override |
| | | public UserInfo userInfo(String tenantId, String account, UserEnum userEnum) { |
| | | User user = baseMapper.getUser(tenantId, account); |
| | | return buildUserInfo(user, userEnum); |
| | | List<User> list = baseMapper.selectUserByPhoneOrAccount(tenantId, account); |
| | | if (list.size()>0){ |
| | | return buildUserInfo(list.get(0), userEnum); |
| | | } |
| | | return buildUserInfo(null, userEnum); |
| | | } |
| | | |
| | | private UserInfo buildUserInfo(User user) { |
| | |
| | | return baseMapper.customizeGetList(user); |
| | | } |
| | | |
| | | /** |
| | | * 根据手机号码查询用户信息 |
| | | * @param tenantId |
| | | * @param phone |
| | | * @return |
| | | */ |
| | | @Override |
| | | public List<User> userInfoByPhone(String tenantId, String phone) { |
| | | return list(Wrappers.<User>query().lambda().eq(User::getTenantId, tenantId).eq(User::getPhone, phone).eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED)); |
| | | } |
| | | |
| | | /** |
| | | * 根据手机号码或者账户查询用户信息 |
| | | * @param tenantId 租户id |
| | | * @param key 账户或者手机号 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public List<User> userInfoByPhoneOrAccount(String tenantId, String key) { |
| | | return baseMapper.selectUserByPhoneOrAccount(tenantId,key); |
| | | } |
| | | } |