| | |
| | | package com.ruoyi.system.api; |
| | | |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestHeader; |
| | | import com.ruoyi.common.core.constant.SecurityConstants; |
| | | import com.ruoyi.common.core.constant.ServiceNameConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.factory.RemoteUserFallbackFactory; |
| | | import com.ruoyi.system.api.model.LoginUser; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestHeader; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | /** |
| | | * 用户服务 |
| | |
| | | */ |
| | | @PostMapping("/user/register") |
| | | public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); |
| | | |
| | | |
| | | @PutMapping("/user/change-password") |
| | | public R<?> changePassword(@RequestParam("username") String username, |
| | | @RequestParam("password") String password, |
| | | @RequestHeader(SecurityConstants.FROM_SOURCE) String source); |
| | | } |
| | |
| | | package com.ruoyi.system.api.factory; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.system.api.RemoteUserService; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.model.LoginUser; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 用户服务降级处理 |
| | |
| | | { |
| | | return R.fail("注册用户失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<?> changePassword(String username, String password, String source) { |
| | | return R.fail("修改密码失败:" + throwable.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.auth.controller; |
| | | |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import com.ruoyi.common.core.constant.SecurityConstants; |
| | | import com.ruoyi.system.api.RemoteUserService; |
| | | import com.ruoyi.system.api.domain.SysRole; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.feignClient.SysUserClient; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import com.ruoyi.auth.form.ChangePasswordBody; |
| | | import com.ruoyi.auth.form.LoginBody; |
| | | import com.ruoyi.auth.form.RegisterBody; |
| | | import com.ruoyi.auth.service.SysLoginService; |
| | | import com.ruoyi.auth.utils.HuaWeiSMSUtil; |
| | | import com.ruoyi.common.core.constant.CacheConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.utils.JwtUtils; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.redis.service.RedisService; |
| | | import com.ruoyi.common.security.auth.AuthUtil; |
| | | import com.ruoyi.common.security.service.TokenService; |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.system.api.domain.SysRole; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.feignClient.SysUserClient; |
| | | import com.ruoyi.system.api.model.LoginUser; |
| | | |
| | | import java.util.*; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * token 控制 |
| | |
| | | */ |
| | | @RestController |
| | | @Api(tags = "认证授权") |
| | | @Slf4j |
| | | public class TokenController |
| | | { |
| | | @Autowired |
| | |
| | | private SysLoginService sysLoginService; |
| | | @Autowired |
| | | private SysUserClient userClient; |
| | | |
| | | @Autowired |
| | | private RedisService redisService; |
| | | @PostMapping("login") |
| | | @ApiOperation(value = "用户登录") |
| | | public R<?> login(@RequestBody LoginBody form) |
| | |
| | | sysLoginService.register(registerBody.getUsername(), registerBody.getPassword()); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @GetMapping("send-verification-code") |
| | | @ApiOperation(value = "发送验证码") |
| | | public R<?> changePassword(@RequestParam("username") String username) { |
| | | //校验手机号码 |
| | | SysUser sysUser = userClient.queryUserByUserName(username).getData(); |
| | | if (StringUtils.isNull(sysUser)) { |
| | | return R.fail("用户不存在"); |
| | | } |
| | | String code = RandomUtil.randomNumbers(6); |
| | | try { |
| | | //TODO 发送短信未配置 |
| | | HuaWeiSMSUtil.sendSms(code, sysUser.getUserName(), "8823121426646", |
| | | "cf1707ec44694627b1b483b0277e12fd"); |
| | | } catch (Exception e) { |
| | | log.error("【修改密码】发送短信失败", e); |
| | | return R.fail("发送失败"); |
| | | } |
| | | //将验证码放入redis |
| | | redisService.setCacheObject( |
| | | CacheConstants.CHANGE_PASSWORD_CAPTCHA_CODE_KEY + sysUser.getUserName(), code, 5L, |
| | | TimeUnit.MINUTES); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @PutMapping("change-password") |
| | | @ApiOperation(value = "用户修改密码") |
| | | public R<?> changePassword(@RequestBody ChangePasswordBody changePasswordBody) { |
| | | // 用户修改密码 |
| | | sysLoginService.changePassword(changePasswordBody.getUsername(), |
| | | changePasswordBody.getPassword(), changePasswordBody.getVerificationCode()); |
| | | return R.ok(); |
| | | } |
| | | } |
| | | |
| | | |
New file |
| | |
| | | package com.ruoyi.auth.form; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import javax.validation.constraints.NotBlank; |
| | | |
| | | /** |
| | | * @author mitao |
| | | * @date 2024/5/17 |
| | | */ |
| | | @ApiModel(value = "用户修改密码对象", description = "用户修改密码对象") |
| | | public class ChangePasswordBody extends LoginBody { |
| | | |
| | | @ApiModelProperty(value = "验证码", required = true) |
| | | @NotBlank(message = "验证码不能为空") |
| | | private String verificationCode; |
| | | |
| | | public String getVerificationCode() { |
| | | return verificationCode; |
| | | } |
| | | |
| | | public void setVerificationCode(String verificationCode) { |
| | | this.verificationCode = verificationCode; |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.auth.form; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import javax.validation.constraints.NotBlank; |
| | | |
| | | /** |
| | | * 用户登录对象 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @ApiModel(value = "登录对象", description = "用户登录对象") |
| | | public class LoginBody |
| | | { |
| | | /** |
| | | * 用户名 |
| | | */ |
| | | @ApiModelProperty(value = "用户名", required = true) |
| | | @NotBlank(message = "用户名不能为空") |
| | | private String username; |
| | | |
| | | /** |
| | | * 用户密码 |
| | | */ |
| | | @ApiModelProperty(value = "用户密码", required = true) |
| | | @NotBlank(message = "用户密码不能为空") |
| | | private String password; |
| | | |
| | | public String getUsername() |
| | |
| | | package com.ruoyi.auth.service; |
| | | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | import com.ruoyi.common.core.constant.CacheConstants; |
| | | import com.ruoyi.common.core.constant.Constants; |
| | | import com.ruoyi.common.core.constant.SecurityConstants; |
| | |
| | | import com.ruoyi.system.api.RemoteUserService; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.model.LoginUser; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 登录校验方法 |
| | |
| | | } |
| | | recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功"); |
| | | } |
| | | |
| | | public void changePassword(String username, String password, String verificationCode) { |
| | | String verificationCodeCache = Convert.toStr( |
| | | redisService.getCacheObject( |
| | | CacheConstants.CHANGE_PASSWORD_CAPTCHA_CODE_KEY + username)); |
| | | if (StringUtils.isEmpty(verificationCodeCache)) { |
| | | throw new ServiceException("验证码已过期,请重新获取!"); |
| | | } |
| | | if (!verificationCodeCache.equals(verificationCode)) { |
| | | throw new ServiceException("验证码错误,请重新输入!"); |
| | | } |
| | | R<LoginUser> userInfo = remoteUserService.getUserInfo(username, SecurityConstants.INNER); |
| | | if (R.FAIL == userInfo.getCode()) { |
| | | throw new ServiceException(userInfo.getMsg()); |
| | | } |
| | | if (!passwordService.matches(userInfo.getData().getSysUser(), password)) { |
| | | throw new ServiceException("旧密码错误,请重新输入!"); |
| | | } |
| | | remoteUserService.changePassword(username, SecurityUtils.encryptPassword(password), |
| | | SecurityConstants.INNER); |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.auth.utils; |
| | | |
| | | import java.nio.charset.Charset; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Base64; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | import org.apache.commons.codec.binary.Hex; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | import org.apache.http.HttpHeaders; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.NameValuePair; |
| | | import org.apache.http.client.methods.RequestBuilder; |
| | | import org.apache.http.client.utils.URLEncodedUtils; |
| | | import org.apache.http.conn.ssl.NoopHostnameVerifier; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.message.BasicNameValuePair; |
| | | import org.apache.http.ssl.SSLContextBuilder; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | //如果JDK版本是1.8,可使用原生Base64类 |
| | | |
| | | public class HuaWeiSMSUtil { |
| | | |
| | | //无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 |
| | | private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; |
| | | //无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 |
| | | private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | |
| | | sendSms("[\"" + 12356 + "\"]", "18283820718", "8823121426646", |
| | | "cf1707ec44694627b1b483b0277e12fd"); |
| | | // sendSms("[\"17623778642\",\"蓉A-7823\"]","17623778642","8819122535459","6c848255000c4619833ab690e393f906"); |
| | | // sendSms("[\"17623778642\",\"蓉A-7823\",\"2019/12/27\",\"14:00\"]","17623778642","8819122535459","bb13d00d11e043659001a89c72d54cab"); |
| | | } |
| | | |
| | | /** |
| | | * 调用短信 |
| | | * |
| | | * @param code 入参 |
| | | * @param phone 接收短信手机号 |
| | | * @param sender 国内短信签名通道号或国际/港澳台短信通道号 |
| | | * @param templateId 模板ID |
| | | * @throws Exception |
| | | */ |
| | | public static void sendSms(String code, String phone, String sender, String templateId) |
| | | throws Exception { |
| | | //必填,请参考"开发准备"获取如下数据,替换为实际值 |
| | | String url = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI |
| | | String appKey = "tTMBH29Tm6tKKHf882JXob82P1rb"; //APP_Key |
| | | String appSecret = "Ob02q15WAgDZRwW9kDlVPklBSdfR"; //APP_Secret |
| | | |
| | | //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称 |
| | | //国际/港澳台短信不用关注该参数 |
| | | String signature = null; //签名名称 |
| | | |
| | | //必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔 |
| | | String receiver = "+86" + phone; //短信接收人号码 |
| | | |
| | | //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 |
| | | String statusCallBack = ""; |
| | | |
| | | /** |
| | | * 选填,使用无变量模板时请赋空值 String templateParas = ""; |
| | | * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"369751\"]" |
| | | * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]" |
| | | * ${DATE}${TIME}变量不允许取值为空,${TXT_20}变量可以使用英文空格或点号替代空值,${NUM_6}变量可以使用0替代空值 |
| | | * 查看更多模板和变量规范:产品介绍>模板和变量规范 |
| | | */ |
| | | String templateParas = code; //模板变量 |
| | | |
| | | //请求Body,不携带签名名称时,signature请填null |
| | | String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, |
| | | signature); |
| | | if (null == body || body.isEmpty()) { |
| | | System.out.println("body is null."); |
| | | return; |
| | | } |
| | | |
| | | //请求Headers中的X-WSSE参数值 |
| | | String wsseHeader = buildWsseHeader(appKey, appSecret); |
| | | if (null == wsseHeader || wsseHeader.isEmpty()) { |
| | | System.out.println("wsse header is null."); |
| | | return; |
| | | } |
| | | |
| | | //如果JDK版本低于1.8,可使用如下代码 |
| | | //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 |
| | | //CloseableHttpClient client = HttpClients.custom() |
| | | // .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { |
| | | // @Override |
| | | // public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { |
| | | // return true; |
| | | // } |
| | | // }).build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); |
| | | |
| | | //如果JDK版本是1.8,可使用如下代码 |
| | | //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 |
| | | CloseableHttpClient client = HttpClients.custom() |
| | | .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, |
| | | (x509CertChain, authType) -> true).build()) |
| | | .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) |
| | | .build(); |
| | | |
| | | HttpResponse response = client.execute(RequestBuilder.create("POST")//请求方法POST |
| | | .setUri(url) |
| | | .addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded") |
| | | .addHeader(HttpHeaders.AUTHORIZATION, AUTH_HEADER_VALUE) |
| | | .addHeader("X-WSSE", wsseHeader) |
| | | .setEntity(new StringEntity(body)).build()); |
| | | |
| | | System.out.println(response.toString()); //打印响应头域信息 |
| | | System.out.println(EntityUtils.toString(response.getEntity())); //打印响应消息实体 |
| | | } |
| | | |
| | | /** |
| | | * 构造请求Body体 |
| | | * |
| | | * @param sender |
| | | * @param receiver |
| | | * @param templateId |
| | | * @param templateParas |
| | | * @param statusCallbackUrl |
| | | * @param signature | 签名名称,使用国内短信通用模板时填写 |
| | | * @return |
| | | */ |
| | | static String buildRequestBody(String sender, String receiver, String templateId, |
| | | String templateParas, |
| | | String statusCallbackUrl, String signature) { |
| | | if (null == sender || null == receiver || null == templateId || sender.isEmpty() |
| | | || receiver.isEmpty() |
| | | || templateId.isEmpty()) { |
| | | System.out.println("buildRequestBody(): sender, receiver or templateId is null."); |
| | | return null; |
| | | } |
| | | List<NameValuePair> keyValues = new ArrayList<NameValuePair>(); |
| | | |
| | | keyValues.add(new BasicNameValuePair("from", sender)); |
| | | keyValues.add(new BasicNameValuePair("to", receiver)); |
| | | keyValues.add(new BasicNameValuePair("templateId", templateId)); |
| | | if (null != templateParas && !templateParas.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("templateParas", templateParas)); |
| | | } |
| | | if (null != statusCallbackUrl && !statusCallbackUrl.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("statusCallback", statusCallbackUrl)); |
| | | } |
| | | if (null != signature && !signature.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("signature", signature)); |
| | | } |
| | | |
| | | return URLEncodedUtils.format(keyValues, Charset.forName("UTF-8")); |
| | | } |
| | | |
| | | /** |
| | | * 构造X-WSSE参数值 |
| | | * |
| | | * @param appKey |
| | | * @param appSecret |
| | | * @return |
| | | */ |
| | | static String buildWsseHeader(String appKey, String appSecret) { |
| | | if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { |
| | | System.out.println("buildWsseHeader(): appKey or appSecret is null."); |
| | | return null; |
| | | } |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); |
| | | String time = sdf.format(new Date()); //Created |
| | | String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce |
| | | |
| | | byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret); |
| | | String hexDigest = Hex.encodeHexString(passwordDigest); |
| | | |
| | | //如果JDK版本是1.8,请加载原生Base64类,并使用如下代码 |
| | | String passwordDigestBase64Str = Base64.getEncoder() |
| | | .encodeToString(hexDigest.getBytes()); //PasswordDigest |
| | | //如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码 |
| | | //String passwordDigestBase64Str = Base64.encodeBase64String(hexDigest.getBytes(Charset.forName("utf-8"))); //PasswordDigest |
| | | //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正 |
| | | //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", ""); |
| | | |
| | | return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); |
| | | } |
| | | } |
| | |
| | | * 登录IP黑名单 cache key |
| | | */ |
| | | public static final String SYS_LOGIN_BLACKIPLIST = SYS_CONFIG_KEY + "sys.login.blackIPList"; |
| | | |
| | | /** |
| | | * 修改密码验证码 redis key |
| | | */ |
| | | public static final String CHANGE_PASSWORD_CAPTCHA_CODE_KEY = "change_password_captcha_codes:"; |
| | | } |
| | |
| | | package com.ruoyi.system.controller; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.core.web.page.PageInfo; |
| | | |
| | | import com.ruoyi.system.api.model.*; |
| | | import com.ruoyi.system.domain.SysUserRole; |
| | | import com.ruoyi.system.service.*; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.apache.commons.lang3.ArrayUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.core.utils.poi.ExcelUtil; |
| | | import com.ruoyi.common.core.web.controller.BaseController; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.core.web.page.PageInfo; |
| | | import com.ruoyi.common.log.annotation.Log; |
| | | import com.ruoyi.common.log.enums.BusinessType; |
| | | import com.ruoyi.common.security.annotation.InnerAuth; |
| | |
| | | import com.ruoyi.system.api.domain.SysDept; |
| | | import com.ruoyi.system.api.domain.SysRole; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.model.CompanyAddSysUserDto; |
| | | import com.ruoyi.system.api.model.CompanySysUserReq; |
| | | import com.ruoyi.system.api.model.CompanyUserListVo; |
| | | import com.ruoyi.system.api.model.LoginUser; |
| | | import com.ruoyi.system.api.model.SysUserRoleDTO; |
| | | import com.ruoyi.system.api.model.TRepairShopAdd; |
| | | import com.ruoyi.system.api.model.TRepairShopAddDto; |
| | | import com.ruoyi.system.domain.SysUserRole; |
| | | import com.ruoyi.system.service.ISysConfigService; |
| | | import com.ruoyi.system.service.ISysDeptService; |
| | | import com.ruoyi.system.service.ISysPermissionService; |
| | | import com.ruoyi.system.service.ISysPostService; |
| | | import com.ruoyi.system.service.ISysRoleService; |
| | | import com.ruoyi.system.service.ISysUserRoleService; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import org.apache.commons.lang3.ArrayUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | /** |
| | | * 用户信息 |
| | |
| | | } |
| | | |
| | | /** |
| | | * 获取当前用户信息 |
| | | */ |
| | | @InnerAuth |
| | | @Log(title = "用户管理", businessType = BusinessType.UPDATE) |
| | | @PutMapping("/change-password") |
| | | public R<LoginUser> info(@RequestParam("username") String username, |
| | | @RequestParam("password") String password) { |
| | | SysUser user = userService.selectUserByUserName(username); |
| | | user.setPassword(password); |
| | | user.setUpdateBy(SecurityUtils.getUsername()); |
| | | int i = userService.updateUser(user); |
| | | if (i == 1) { |
| | | return R.ok(); |
| | | } else { |
| | | return R.fail(); |
| | | } |
| | | } |
| | | /** |
| | | * 状态修改 |
| | | */ |
| | | @RequiresPermissions("system:user:edit") |
New file |
| | |
| | | package com.ruoyi.system.utils; |
| | | |
| | | import java.nio.charset.Charset; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Base64; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | import org.apache.commons.codec.binary.Hex; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | import org.apache.http.HttpHeaders; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.NameValuePair; |
| | | import org.apache.http.client.methods.RequestBuilder; |
| | | import org.apache.http.client.utils.URLEncodedUtils; |
| | | import org.apache.http.conn.ssl.NoopHostnameVerifier; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.message.BasicNameValuePair; |
| | | import org.apache.http.ssl.SSLContextBuilder; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | //如果JDK版本是1.8,可使用原生Base64类 |
| | | |
| | | public class HuaWeiSMSUtil { |
| | | |
| | | //无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 |
| | | private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; |
| | | //无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 |
| | | private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | |
| | | sendSms("[\""+12356+"\"]","18283820718","8823121426646","cf1707ec44694627b1b483b0277e12fd"); |
| | | |
| | | // sendSms("[\"17623778642\",\"蓉A-7823\"]","17623778642","8819122535459","6c848255000c4619833ab690e393f906"); |
| | | // sendSms("[\"17623778642\",\"蓉A-7823\",\"2019/12/27\",\"14:00\"]","17623778642","8819122535459","bb13d00d11e043659001a89c72d54cab"); |
| | | } |
| | | |
| | | /** |
| | | * 调用短信 |
| | | * @param code 入参 |
| | | * @param phone 接收短信手机号 |
| | | * @param sender 国内短信签名通道号或国际/港澳台短信通道号 |
| | | * @param templateId 模板ID |
| | | * @throws Exception |
| | | */ |
| | | public static void sendSms(String code,String phone,String sender,String templateId) throws Exception{ |
| | | //必填,请参考"开发准备"获取如下数据,替换为实际值 |
| | | String url = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI |
| | | String appKey = "tTMBH29Tm6tKKHf882JXob82P1rb"; //APP_Key |
| | | String appSecret = "Ob02q15WAgDZRwW9kDlVPklBSdfR"; //APP_Secret |
| | | |
| | | //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称 |
| | | //国际/港澳台短信不用关注该参数 |
| | | String signature = null; //签名名称 |
| | | |
| | | //必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔 |
| | | String receiver = "+86"+phone; //短信接收人号码 |
| | | |
| | | //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 |
| | | String statusCallBack = ""; |
| | | |
| | | /** |
| | | * 选填,使用无变量模板时请赋空值 String templateParas = ""; |
| | | * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"369751\"]" |
| | | * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]" |
| | | * ${DATE}${TIME}变量不允许取值为空,${TXT_20}变量可以使用英文空格或点号替代空值,${NUM_6}变量可以使用0替代空值 |
| | | * 查看更多模板和变量规范:产品介绍>模板和变量规范 |
| | | */ |
| | | String templateParas = code; //模板变量 |
| | | |
| | | //请求Body,不携带签名名称时,signature请填null |
| | | String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature); |
| | | if (null == body || body.isEmpty()) { |
| | | System.out.println("body is null."); |
| | | return; |
| | | } |
| | | |
| | | //请求Headers中的X-WSSE参数值 |
| | | String wsseHeader = buildWsseHeader(appKey, appSecret); |
| | | if (null == wsseHeader || wsseHeader.isEmpty()) { |
| | | System.out.println("wsse header is null."); |
| | | return; |
| | | } |
| | | |
| | | //如果JDK版本低于1.8,可使用如下代码 |
| | | //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 |
| | | //CloseableHttpClient client = HttpClients.custom() |
| | | // .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { |
| | | // @Override |
| | | // public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { |
| | | // return true; |
| | | // } |
| | | // }).build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); |
| | | |
| | | //如果JDK版本是1.8,可使用如下代码 |
| | | //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 |
| | | CloseableHttpClient client = HttpClients.custom() |
| | | .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, |
| | | (x509CertChain, authType) -> true).build()) |
| | | .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) |
| | | .build(); |
| | | |
| | | HttpResponse response = client.execute(RequestBuilder.create("POST")//请求方法POST |
| | | .setUri(url) |
| | | .addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded") |
| | | .addHeader(HttpHeaders.AUTHORIZATION, AUTH_HEADER_VALUE) |
| | | .addHeader("X-WSSE", wsseHeader) |
| | | .setEntity(new StringEntity(body)).build()); |
| | | |
| | | System.out.println(response.toString()); //打印响应头域信息 |
| | | System.out.println(EntityUtils.toString(response.getEntity())); //打印响应消息实体 |
| | | } |
| | | |
| | | /** |
| | | * 构造请求Body体 |
| | | * @param sender |
| | | * @param receiver |
| | | * @param templateId |
| | | * @param templateParas |
| | | * @param statusCallbackUrl |
| | | * @param signature | 签名名称,使用国内短信通用模板时填写 |
| | | * @return |
| | | */ |
| | | static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, |
| | | String statusCallbackUrl, String signature) { |
| | | if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() |
| | | || templateId.isEmpty()) { |
| | | System.out.println("buildRequestBody(): sender, receiver or templateId is null."); |
| | | return null; |
| | | } |
| | | List<NameValuePair> keyValues = new ArrayList<NameValuePair>(); |
| | | |
| | | keyValues.add(new BasicNameValuePair("from", sender)); |
| | | keyValues.add(new BasicNameValuePair("to", receiver)); |
| | | keyValues.add(new BasicNameValuePair("templateId", templateId)); |
| | | if (null != templateParas && !templateParas.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("templateParas", templateParas)); |
| | | } |
| | | if (null != statusCallbackUrl && !statusCallbackUrl.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("statusCallback", statusCallbackUrl)); |
| | | } |
| | | if (null != signature && !signature.isEmpty()) { |
| | | keyValues.add(new BasicNameValuePair("signature", signature)); |
| | | } |
| | | |
| | | return URLEncodedUtils.format(keyValues, Charset.forName("UTF-8")); |
| | | } |
| | | |
| | | /** |
| | | * 构造X-WSSE参数值 |
| | | * @param appKey |
| | | * @param appSecret |
| | | * @return |
| | | */ |
| | | static String buildWsseHeader(String appKey, String appSecret) { |
| | | if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { |
| | | System.out.println("buildWsseHeader(): appKey or appSecret is null."); |
| | | return null; |
| | | } |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); |
| | | String time = sdf.format(new Date()); //Created |
| | | String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce |
| | | |
| | | byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret); |
| | | String hexDigest = Hex.encodeHexString(passwordDigest); |
| | | |
| | | //如果JDK版本是1.8,请加载原生Base64类,并使用如下代码 |
| | | String passwordDigestBase64Str = Base64.getEncoder().encodeToString(hexDigest.getBytes()); //PasswordDigest |
| | | //如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码 |
| | | //String passwordDigestBase64Str = Base64.encodeBase64String(hexDigest.getBytes(Charset.forName("utf-8"))); //PasswordDigest |
| | | //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正 |
| | | //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", ""); |
| | | |
| | | return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); |
| | | } |
| | | } |