0
点赞
收藏
分享

微信扫一扫

网络工程师----第四十七天

前端王祖蓝 2024-06-05 阅读 8

spring boot 集成阿里云短信服务实现登录

引入依赖
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>dysmsapi20170525</artifactId>
  <version>2.0.23</version>
</dependency>
配置文件
aliyun:
  sms:
    access-key-id: access-key
    access-key-secret: access-key-secret
    endpoint: dysmsapi.aliyuncs.com
获取配置文件的内容 properties
package com.orchids.sms.web.custom.sms;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @ Author qwh
 * @ Date 2024/6/3 16:31
 */
@Data
@ConfigurationProperties(prefix = "aliyun.sms")
public class AliyunSMSProperties {

    private String accessKeyId;

    private String accessKeySecret;

    private String endpoint;
}

package com.orchids.sms.web.custom.sms;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.teaopenapi.models.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(AliyunSMSProperties.class)
//当配置文件中没有aliyun.sms.endpoint 也不会报错 有就读取
@ConditionalOnProperty(name = "aliyun.sms.endpoint")   
public class AliyunSMSConfiguration {


    @Autowired
    private AliyunSMSProperties properties;

    @Bean  //交给spring 管理有需要就自动专配
    public Client smsClient() {
        Config config = new Config();
        config.setAccessKeyId(properties.getAccessKeyId());
        config.setAccessKeySecret(properties.getAccessKeySecret());
        config.setEndpoint(properties.getEndpoint());
        try {
            return new Client(config);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}
编写生成验证码工具类
package com.orchids.sms.web.custom.utils;

import java.util.Random;

public class CodeUtil {
    public static String getCode(int length) {
        StringBuilder builder = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            builder.append(random.nextInt(10));
        }
        return builder.toString();
    }
}

发送短信
  1. sevice
package com.orchids.sms.web.service;

public interface SmsService {
    void sendCode(String phone, String Code);
}
  1. serviceImpl 测试阿里云短信服务格式必须是这个
package com.orchids.sms.web.service.impl;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.orchids.sms.web.service.SmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SmsServiceImpl implements SmsService {
    @Autowired
    private Client client;


    @Override
    public void sendCode(String phone, String code) {
        SendSmsRequest smsRequest = new SendSmsRequest();
        smsRequest.setPhoneNumbers(phone);
        smsRequest.setSignName("阿里云短信测试");
        smsRequest.setTemplateCode("SMS_154950909");
        smsRequest.setTemplateParam("{\"code\":\"" + code + "\"}");
        System.out.println("---------------"+code);
        try {
            client.sendSms(smsRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
测试发送短信
package com.orchids.sms.web.service;

import com.orchids.sms.web.custom.utils.CodeUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @ Author qwh
 * @ Date 2024/6/4 8:48
 */
@SpringBootTest
class SmsServiceTest {
    @Autowired
    private SmsService smsService;
    @Test
    void sendCode() {
        smsService.sendCode("phone", CodeUtil.getCode(4));
    }
}
获取登录接口

阿里云发送验证码给用户 --》用户输入验证码
后端登录 首先生成验证码 调用阿里云验证码API发送验证码 并将验证码保存到redis设置过期时间 用户输入验证码后和redis中进行比较 成功生成登录token
引入依赖

<!--官方文档:https://github.com/jwtk/jjwt#install-jdk-maven -->
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-api</artifactId>
  <version>0.11.2</version>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-impl</artifactId>
  <scope>runtime</scope>
  <version>0.11.2</version>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-jackson</artifactId>
  <scope>runtime</scope>
  <version>0.11.2</version>
</dependency>
编写生成token的工具类
package com.orchids.sms.web.custom.utils;



import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;

/**
 * @Author qwh
 * @Date 2024/6/2 21:01
 */
public class JwtUtil {
    private static long tokenExpiration = 60  * 60 * 1000L;
    public static SecretKey secretKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());
    public static String createToken(Long userId,String username){
        String token  = Jwts.builder().
                setSubject("USER_INFO").
                setExpiration(new Date(System.currentTimeMillis()+tokenExpiration)).
                claim("userId",userId).
                claim("username",username).
                signWith(secretKey, SignatureAlgorithm.HS256).
                compact();
        return token;
    }
    public static Claims parsToken(String token){
        if (token==null) {
            throw new SmsException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
        }
        try {
        JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
            Jws<Claims> claims = jwtParser.parseClaimsJws(token);
            return claims.getBody();
        } catch (ExpiredJwtException e) {
            throw new SmsException(ResultCodeEnum.TOKEN_EXPIRED);
        } catch (JwtException e){
            throw new SmsException(ResultCodeEnum.TOKEN_INVALID);
        }
    }

    public static void main(String[] args) {
        System.out.println(createToken(9L,"123123"));
    }
}

获取验证码
  1. controller
package com.orchids.sms.web.controller;

import com.orchids.sms.web.custom.login.LoginUserHolder;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.result.Result;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.entity.vo.UserInfoVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.UserInfoService;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @ Author qwh
 * @ Date 2024/6/4 1:10
 */
@Tag(name = "Sms测试")
@RestController
@RequestMapping("/Sms")
public class LoginController {
    @Autowired
    private LoginService loginService;

    @GetMapping("getCode")
    @Operation(summary = "获取短信验证码")
    public Result getCode(@RequestParam String phone) {
        loginService.getCode(phone);
        return Result.ok();
    }
}
  1. service
package com.orchids.sms.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.custom.utils.CodeUtil;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.pojo.BaseStatus;
import com.orchids.sms.web.entity.pojo.RedisConstant;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.SmsService;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private SmsService smsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserInfoService userInfoService;


    @Override
    public void getCode(String phone) {
        //1. 检查手机号码是否为空
        if (!StringUtils.hasText(phone)) {
            throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }
        String key = RedisConstant.APP_LOGIN_PREFIX+phone;
        Boolean hasKey = stringRedisTemplate.hasKey(key);
        if (hasKey){
            Long ttl = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
            if (RedisConstant.APP_LOGIN_CODE_TTL_SEC-ttl  < 30 ) {
                throw new SmsException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }else {
                String code = CodeUtil.getCode(6);
                smsService.sendCode(phone,code);
                stringRedisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
            }
        }else {
            String code = CodeUtil.getCode(6);
            smsService.sendCode(phone,code);
            stringRedisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
        }
    }
}
登录
  1. controller
@Tag(name = "Sms测试")
@RestController
@RequestMapping("/Sms")
public class LoginController {
    @Autowired
    private LoginService loginService;
    @Autowired
    private UserInfoService userInfoService;

    @GetMapping("getCode")
    @Operation(summary = "获取短信验证码")
    public Result getCode(@RequestParam String phone) {
        loginService.getCode(phone);
        return Result.ok();
    }

    @PostMapping("login")
    @Operation(summary = "登录")
    public Result<String> login(@RequestBody LoginVo loginVo) {
        String token = loginService.login(loginVo);
        return Result.ok(token);
    }
}
  1. service
package com.orchids.sms.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.custom.utils.CodeUtil;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.pojo.BaseStatus;
import com.orchids.sms.web.entity.pojo.RedisConstant;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.SmsService;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private SmsService smsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserInfoService userInfoService;


    @Override
    public String login(LoginVo loginVo) {
        //判断手机号码和验证码是否为空
        if (!StringUtils.hasText(loginVo.getPhone())) {
            throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }
        if (!StringUtils.hasText(loginVo.getCode())){
            throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
        }
        //校验验证码
        String key = RedisConstant.APP_LOGIN_PREFIX + loginVo.getPhone();
        String code = stringRedisTemplate.opsForValue().get(key);
        if (code==null){
            throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
        }
        if (!code.equals(loginVo.getCode())) {
            throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }
        //判断是否用户是否存在 不存在注册
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getPhone,loginVo.getPhone());
        UserInfo userInfo = userInfoService.getOne(queryWrapper);
        if (userInfo==null) {
            userInfo = new UserInfo();
            userInfo.setPhone(loginVo.getPhone());
            userInfo.setStatus(BaseStatus.ENABLE);
            userInfo.setNickname("用户-"+loginVo.getPhone().substring(6));
            userInfoService.save(userInfo);
        }
        //判断用户是否被禁用
        if (userInfo.getStatus().equals(BaseStatus.DISABLE)) {
            throw new SmsException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
        }
        //返回token
        return JwtUtil.createToken(userInfo.getId(), loginVo.getPhone());
    }
}
登录后获取登录信息
  1. controller
    @GetMapping("info")
    @Operation(summary = "获取登录用户信息")
    public Result<UserInfoVo> info(@RequestHeader("access-token")String token) {
        Claims claims = JwtUtil.parsToken(token);
        Long userId = claims.get("userId", Long.class);
        System.out.println(userId);
        UserInfoVo userInfoVo = userInfoService.getUserInfoById(userId);
        return Result.ok(userInfoVo);
    }
  1. service
package com.orchids.sms.web.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.vo.UserInfoVo;
import com.orchids.sms.web.mapper.UserInfoMapper;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
    implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public UserInfoVo getUserInfoById(Long userId) {
        System.out.println(userId);
        UserInfo userInfo = userInfoMapper.selectById(userId);
        System.out.println(userInfo.toString());

        return new UserInfoVo(userInfo.getNickname(), userInfo.getAvatarUrl());
    }
}

测试 通过 这个案例是基于我自己的程序 但是其他程序逻辑大差不多查
其中的枚举类 不同的业务会给出的 如果没有大不了自己编写
全局错误配置 按照自己的业务进行编写 以下是这个案例的代码

package com.orchids.sms.web.custom.exception;


import com.orchids.sms.web.entity.result.ResultCodeEnum;
import lombok.Data;

/**
 * @Author qwh
 * @Date 2024/6/1 20:18
 */
@Data
public class SmsException extends RuntimeException {

    //异常状态码
    private Integer code;
    /**
     * 通过状态码和错误消息创建异常对象
     * @param message
     * @param code
     */
    public SmsException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    /**
     * 根据响应结果枚举对象创建异常对象
     * @param resultCodeEnum
     */
    public SmsException(ResultCodeEnum resultCodeEnum) {
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }

    @Override
    public String toString() {
        return "LovehouseException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}

完整的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.orchids</groupId>
  <artifactId>Sms</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>Sms</name>
  <description>Sms</description>
  <properties>
    <java.version>17</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>3.0.2</spring-boot.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
      <version>4.1.0</version>
    </dependency>
    <dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>dysmsapi20170525</artifactId>
      <version>2.0.23</version>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>3.2.4</version>
    </dependency>
    <!--官方文档:https://github.com/jwtk/jjwt#install-jdk-maven -->
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-api</artifactId>
      <version>0.11.2</version>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-impl</artifactId>
      <scope>runtime</scope>
      <version>0.11.2</version>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-jackson</artifactId>
      <scope>runtime</scope>
      <version>0.11.2</version>
    </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.orchids.sms.SmsApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

application.yaml

# 应用服务 WEB 访问端口
server:
  port: 8080

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
    username: 数据库用户名
    password: 数据库密码
    hikari:
      connection-test-query: SELECT 1 # 自动检测连接
      connection-timeout: 60000 #数据库连接超时时间,默认30秒
      idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)
      max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      maximum-pool-size: 12 #连接池最大连接数,默认是10
      minimum-idle: 10 #最小空闲连接数量
      pool-name: SPHHikariPool # 连接池名称
  data:
    redis:
      host: localhost
      port: 6379
      database: 0
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
aliyun:
  sms:
    access-key-id: 你的阿里云assesskey
    access-key-secret: 你的阿里云accesskeysecret
    endpoint: dysmsapi.aliyuncs.com

举报

相关推荐

0 条评论