package com.fuyuanshen.app.controller; import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.exception.NotLoginException; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import com.alibaba.fastjson.JSON; import com.fuyuanshen.app.model.AppRegisterBody; import com.fuyuanshen.app.model.AppSmsLoginBody; import com.fuyuanshen.app.service.AppLoginService; import com.fuyuanshen.app.service.AppRegisterService; import com.fuyuanshen.common.core.constant.Constants; import com.fuyuanshen.common.core.constant.GlobalConstants; import com.fuyuanshen.common.core.constant.SystemConstants; import com.fuyuanshen.common.core.domain.R; import com.fuyuanshen.common.core.domain.model.AppPasswordLoginBody; import com.fuyuanshen.common.core.domain.model.RegisterBody; import com.fuyuanshen.common.core.domain.model.SmsLoginBody; import com.fuyuanshen.common.core.enums.LoginType; import com.fuyuanshen.common.core.utils.*; import com.fuyuanshen.common.encrypt.annotation.ApiEncrypt; import com.fuyuanshen.common.json.utils.JsonUtils; import com.fuyuanshen.common.ratelimiter.annotation.RateLimiter; import com.fuyuanshen.common.redis.utils.RedisUtils; import com.fuyuanshen.common.satoken.utils.LoginHelper; import com.fuyuanshen.common.tenant.helper.TenantHelper; import com.fuyuanshen.system.domain.bo.SysTenantBo; import com.fuyuanshen.system.domain.vo.SysClientVo; import com.fuyuanshen.system.domain.vo.SysDictDataVo; import com.fuyuanshen.system.domain.vo.SysTenantVo; import com.fuyuanshen.system.service.ISysClientService; import com.fuyuanshen.system.service.ISysConfigService; import com.fuyuanshen.system.service.ISysDictTypeService; import com.fuyuanshen.system.service.ISysTenantService; import com.fuyuanshen.web.domain.Dto.SystemVersionDto; import com.fuyuanshen.web.domain.vo.LoginTenantVo; import com.fuyuanshen.web.domain.vo.LoginVo; import com.fuyuanshen.web.domain.vo.TenantListVo; import com.fuyuanshen.web.service.IAuthStrategy; import com.fuyuanshen.web.service.SysRegisterService; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.core.factory.SmsFactory; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.net.URL; import java.time.Duration; import java.util.LinkedHashMap; import java.util.ArrayList; import java.util.List; import static com.fuyuanshen.common.core.constant.GlobalConstants.DEVICE_SHARE_CODES_KEY; import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; /** * APP认证 * * @author Lion Li */ @Slf4j @SaIgnore @RequiredArgsConstructor @RestController @RequestMapping("/app/auth") public class AppAuthController { private final AppLoginService loginService; private final AppRegisterService registerService; private final ISysConfigService configService; private final ISysTenantService tenantService; private final ISysClientService clientService; private final ISysDictTypeService dictTypeService; /** * 登录方法 * * @return 结果 */ // @ApiEncrypt @PostMapping("/login") public R login(@RequestBody AppSmsLoginBody appSmsLoginBody) { // SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); String loginType = appSmsLoginBody.getLoginType(); String body = ""; // 授权类型和客户端id String clientId = ""; String grantType = ""; String tenantId = appSmsLoginBody.getTenantId(); ValidatorUtils.validate(appSmsLoginBody); if("2".equals(loginType)){ AppPasswordLoginBody loginBody = new AppPasswordLoginBody(); loginBody.setUsername(appSmsLoginBody.getPhonenumber()); loginBody.setPassword(appSmsLoginBody.getLoginPassword()); loginBody.setClientId("835b15335d389c9fcfdf99421fa8019b"); loginBody.setGrantType("appPassword"); clientId = loginBody.getClientId(); grantType = loginBody.getGrantType(); body = JsonUtils.toJsonString(loginBody); }else{ SmsLoginBody loginBody = new SmsLoginBody(); loginBody.setPhonenumber(appSmsLoginBody.getPhonenumber()); loginBody.setSmsCode(appSmsLoginBody.getSmsCode()); loginBody.setTenantId(appSmsLoginBody.getTenantId()); loginBody.setClientId("ca839698e245d60aa2f0e59bd52b34f8"); loginBody.setGrantType("appSms"); clientId = loginBody.getClientId(); grantType = loginBody.getGrantType(); body = JsonUtils.toJsonString(loginBody); } SysClientVo client = clientService.queryByClientId(clientId); // 查询不到 client 或 client 内不包含 grantType if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); return R.fail(MessageUtils.message("auth.grant.type.error")); } else if (!SystemConstants.NORMAL.equals(client.getStatus())) { return R.fail(MessageUtils.message("auth.grant.type.blocked")); } // 校验租户 // loginService.checkTenant(loginBody.getTenantId()); loginService.checkTenant(tenantId); // 登录 LoginVo loginVo = IAuthStrategy.login(body, client, grantType); return R.ok(loginVo); } /** * 用户注销 */ @PostMapping("/cancelAccount") public R cancelAccount() { loginService.cancelAccount(); return R.ok("用户注销成功"); } /** * 用户注册 */ @PostMapping("/register") public R register(@Validated @RequestBody AppRegisterBody body) { registerService.register(body); return R.ok(); } /** * 找回密码 */ @PostMapping("/forgetPassword") public R forgetPassword(@Validated @RequestBody AppRegisterBody body) { registerService.forgetPassword(body); return R.ok(); } /** * 用户注册短信验证码 * * @param phonenumber 用户手机号 */ @SaIgnore @RateLimiter(key = "#phonenumber", time = 60, count = 1) @GetMapping("/registerSmsCode") public R registerSmsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { String key = GlobalConstants.REGISTER_CODE_KEY + phonenumber; String code = RandomUtil.randomNumbers(4); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); LinkedHashMap map = new LinkedHashMap<>(1); map.put("code", code); SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, map); if (!smsResponse.isSuccess()) { return R.fail(smsResponse.getData().toString()); } return R.ok(); } /** * 找回密码短信验证码 * * @param phonenumber 用户手机号 */ @SaIgnore @RateLimiter(key = "#phonenumber", time = 60, count = 1) @GetMapping("/forgetPasswordSmsCode") public R forgetPasswordSmsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { String key = GlobalConstants.FORGET_PASSWORD_CODE_KEY + phonenumber; String code = RandomUtil.randomNumbers(4); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); LinkedHashMap map = new LinkedHashMap<>(1); map.put("code", code); SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, map); if (!smsResponse.isSuccess()) { return R.fail(smsResponse.getData().toString()); } return R.ok(); } /** * 登录页面租户下拉框 * * @return 租户列表 */ @GetMapping("/tenant/list") public R tenantList(HttpServletRequest request) throws Exception { // 返回对象 LoginTenantVo result = new LoginTenantVo(); boolean enable = TenantHelper.isEnable(); result.setTenantEnabled(enable); // 如果未开启租户这直接返回 if (!enable) { return R.ok(result); } List tenantList = tenantService.queryList(new SysTenantBo()); List voList = MapstructUtils.convert(tenantList, TenantListVo.class); try { // 如果只超管返回所有租户 if (LoginHelper.isSuperAdmin()) { result.setVoList(voList); return R.ok(result); } } catch (NotLoginException ignored) { } // 获取域名 String host; String referer = request.getHeader("referer"); if (StringUtils.isNotBlank(referer)) { // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试 host = referer.split("//")[1].split("/")[0]; } else { host = new URL(request.getRequestURL().toString()).getHost(); } // 根据域名进行筛选 List list = StreamUtils.filter(voList, vo -> StringUtils.equalsIgnoreCase(vo.getDomain(), host)); result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); return R.ok(result); } @GetMapping("/test") public void testSend() { // 在创建完SmsBlend实例后,再未手动调用注销的情况下框架会持有该实例,可以直接通过指定configId来获取想要的配置,如果你想使用 // 负载均衡形式获取实例,只要使用getSmsBlend的无参重载方法即可,如果你仅有一个配置,也可以使用该方法 SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsResponse smsResponse = smsBlend.sendMessage("18656573389", "123"); } /** * 获取app版本 * @return */ @GetMapping("/version") public R> getAppVersion() { String versionKey = GLOBAL_REDIS_KEY + "System:Version:Xinghan"; // 缓存告警消息到Redis String versionJson = RedisUtils.getCacheObject(versionKey); if (StringUtils.isBlank(versionJson)) { // hutool 工具,可用 StringUtils.isBlank 代替 return R.fail(versionJson); } List list = JSON.parseArray(versionJson, SystemVersionDto.class); return R.ok(list); } }