阿里云短信服务实现免密登陆

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u012211603/article/details/79366136

使用阿里云的短信服务,实现免密登陆。

一. 阿里云短信服务申请。

1、首先,得有个阿里云账号,在控制台找到短信服务。

2、 在签名管理中根据步骤添加签名,这个之后就是你验证码短信中最开始的【】中的内容,譬如阿里云的短信,【阿里云】xxx 。申请可能审核不通过,它会提示你原因,我一开始未通过是因为在申请说明中需要填写你项目的网址,或者项目名称。这个签名后面会用到。

3、在模板管理中添加模板,上面有模板库让你参考,譬如,“您的验证码:${code},您正进行身份验证,打死不告诉别人!”,根据自己需求可以再改改,只要不是一些敏感内容即可。通过后有个模板CODE后面会用到,SMS_前缀加一串数字的那个。

二. 密钥申请&下载短信发送API的SDK

如图:
这里写图片描述

在Access Key管理中创建,可以获得公钥和私钥,之后会使用。

我使用的是JAVA的,SDK包里包括一个aliyun-java-sdk-core包,一个alicom-dysms-api包。

下载后放入项目中,我选择新建一个lib文件夹,然后再pom文件中添加依赖

<!-- 阿里云短信服务 -->
		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-core</artifactId>
			<version>3.3.1</version>
			<scope>system</scope>
			<systemPath>${project.basedir}/lib/aliyun-java-sdk-core-3.3.1.jar</systemPath>
		</dependency>
		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
			<version>1.0.0</version>
			<scope>system</scope>
			<systemPath>${project.basedir}/lib/aliyun-java-sdk-dysmsapi-1.0.0.jar</systemPath>
		</dependency>

然后在配置文件中添加阿里云短信的配置,我是在全局配置文件application.properties中添加,

# 阿里云短信
aliyun.sms.accessKey=你的
aliyun.sms.accessKeySecret=你的
aliyun.sms.template.code=SMS_你的

三. 发送验证码功能

可以参考其样例程序。
接口就不贴了。

@Service
public class SmsServiceImpl implements ISmsService, InitializingBean {

    @Value("${aliyun.sms.accessKey}")
    private String accessKey;

    @Value("${aliyun.sms.accessKeySecret}")
    private String scretKey;

    @Value("${aliyun.sms.template.code}")
    private String templateCode;

    private IAcsClient acsClient;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String SMS_CODE_CONTENT_PREFIX = "SMS::CODE:CONTENT::";

    private static final String[] NUMS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

    private static final Random random = new Random();

    @Override
    public ServiceResult<String> sendSms(String telephone) {
        // 检查间隔时间
        String gapKey = "SMS::CODE:INTERVAL::" + telephone;
        //从redis缓存中通过key获取
        String result = redisTemplate.opsForValue().get(gapKey);
        //获取得到说明缓存中已经有验证码信息了,稍后再请求
        if (result != null) {
            return new ServiceResult<String>(false, "请求次数太频繁,请稍后再试!");
        }
			
        // 否则,获取短信验证码
        String code = generateRandomSmsCode();
        //短信模板参数
        String templateParam = String.format("{\"code\": \"%s\"}", code);

        // 组装请求对象
        SendSmsRequest request = new SendSmsRequest();

        // 使用post提交
        request.setMethod(MethodType.POST);
        // 代发手机号
        request.setPhoneNumbers(telephone);
        // 给模板传参
        request.setTemplateParam(templateParam);
        // 短信模板 SMS_CODE
        request.setTemplateCode(templateCode);
        // 短信签名
        request.setSignName("Orcas栈");

        boolean success = false;
        try {
            SendSmsResponse response = acsClient.getAcsResponse(request);
            //判断sms验证码发送是否成功
            if ("OK".equals(response.getCode())) {
                success = true;
            } else {
                return new ServiceResult<String>(false, "验证码发送失败!");
            }
        } catch (ClientException e) {
            e.printStackTrace();
        }

        if (success) {
            // 短信发送成功, 存入redis缓存中
            redisTemplate.opsForValue().set(gapKey, code, 60, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(SMS_CODE_CONTENT_PREFIX + telephone, code, 10, TimeUnit.MINUTES);
            return ServiceResult.of(code);
        } else {
            return new ServiceResult<String>(false, "服务忙,请稍后重试!");
        }
    }

    @Override
    public String getSmsCode(String telephone) {
        return this.redisTemplate.opsForValue().get(SMS_CODE_CONTENT_PREFIX + telephone);
    }

    @Override
    public void remove(String telephone) {
        this.redisTemplate.delete(SMS_CODE_CONTENT_PREFIX + telephone);
    }

	//
    @Override
    public void afterPropertiesSet() throws Exception {
        // 设置超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        // 初始化ascClient
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKey, scretKey);

        String product = "Dysmsapi";   // 短信API产品名称,固定
        String domain = "dysmsapi.aliyuncs.com";   // 短信API产品域名,固定

        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        this.acsClient = new DefaultAcsClient(profile);

    }

    /**
     *  6位验证码生成器
     * @return
     */
    private static String generateRandomSmsCode() {
        StringBuilder sb = new StringBuilder();
        //NUMS[10]
        for (int i = 0; i < 6; i++) {
            int index = random.nextInt(10);
            sb.append(NUMS[index]);
        }

        return sb.toString();
    }
}

Controller层:

 @GetMapping("/sms/code")
    @ResponseBody
    public ApiResponse smsCode(@RequestParam("telephone") String telephone) {
        if (!LoginUserUtil.checkTelephone(telephone)) {
            return ApiResponse.ofMessage(HttpStatus.BAD_REQUEST.value(), "请输入正确的手机号!");
        }

        ServiceResult<String> result = smsService.sendSms(telephone);
        if (result.isSuccess()) {
            return ApiResponse.ofSuccess("发送成功!");
        } else {
            return ApiResponse.ofMessage(HttpStatus.BAD_REQUEST.value(), result.getMessage());
        }

    }

成功短信示例:
这里写图片描述

四. 登陆功能

使用的Spring Security管理,部分代码省略。

public class AuthFilter extends UsernamePasswordAuthenticationFilter {

    @Autowired
    private IUserService userService;

    @Autowired
    private ISmsService smsService;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        String name = obtainUsername(request);
        if (!Strings.isNullOrEmpty(name)) {
            //用户名密码登陆
            request.setAttribute("username", name);
            return super.attemptAuthentication(request, response);
        }
        //手机登陆
        String telephone = request.getParameter("telephone");
        if (Strings.isNullOrEmpty(telephone) || !LoginUserUtil.checkTelephone(telephone)) {
            throw new BadCredentialsException("Wrong telephone number");
        }

        User user = userService.findUserByTelephone(telephone);

        String inputCode = request.getParameter("smsCode");
        String sessionCode = smsService.getSmsCode(telephone);

        if (Objects.equals(inputCode, sessionCode)) {
            if (user == null) {
                //手机号未注册 注册该用户
                user = userService.addUserByPhone(telephone);
            }
            return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        } else {
            throw new BadCredentialsException("smsCodeError");
        }
    }
}

@Service
public class UserServiceImpl implements IUserService{

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Override
    public User findUserByName(String userName) {
        User user = userRepository.findByName(userName);
        if (user == null) {
            return null;
        }
        List<Role> roles = roleRepository.findRolesByUserId(user.getId());
        if (roles == null || roles.isEmpty()) {
            throw new DisabledException("权限非法");
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())));
        user.setAuthorityList(authorities);

        return user;
    }

    @Override
    public User findUserByTelephone(String telephone) {
        User user = userRepository.findUserByPhoneNumber(telephone);
        if (user == null) {
            return null;
        }

        List<Role> roles = roleRepository.findRolesByUserId(user.getId());
        if (roles == null || roles.isEmpty()) {
            throw new DisabledException("权限非法");
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())));
        user.setAuthorityList(authorities);

        return user;
    }

    @Override
    @Transactional
    public User addUserByPhone(String telephone) {
        User user = new User();
        user.setPhoneNumber(telephone);
        user.setName(telephone.substring(0, 3) + "****" + telephone.substring(7, telephone.length()));
        user.setCreatTime(new Date());
        user.setLastUpdateTime(new Date());
        user.setLastLoginTime(new Date());

        user = userRepository.save(user);

        Role role = new Role();
        role.setName("USER");
        role.setUserId(user.getId());
        roleRepository.save(role);
        user.setAuthorityList(Lists.newArrayList(new SimpleGrantedAuthority("ROLE_USER")));

        return user;
    }


}

其实只是想记录下如何用阿里云短信服务实现发送验证码,所以后面的可以忽略啦。

猜你喜欢

转载自blog.csdn.net/u012211603/article/details/79366136