uniapp引入阿里云短信业务

                                    主要分为3大部分

1.配置阿里云短信业务

2.uniapp手机登录模块设计以及信息提交

3.后端接收手机登录信息,反馈登录结果

 

项目地址:https://gitee.com/quxianyyy/sms-project

 

一步可以直接参考博主Axn_很优秀的文章,申请获取到key和secret

https://blog.csdn.net/qq_36802111/article/details/82561276?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159109985119724848343926%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=159109985119724848343926&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~baidu_landing_v2~default-4-82561276.pc_v2_rank_blog_v1&utm_term=%E9%98%BF%E9%87%8C%E4%BA%91%E7%9F%AD%E4%BF%A1%E4%B8%9A%E5%8A%A1

第二步在uniapp设计一个手机登录的页面(ui框架是color-ui)

<form @submit="login">
			<view class="cu-form-group">
				<view class="title">手机号码</view>
				<input placeholder="请输入手机号码" name="phoneNumbers" @input="change" maxlength="11" type="number"></input>
				<view class="cu-capsule radius">
					<view class='cu-tag bg-blue '>
						+86
					</view>
					<view class="cu-tag line-blue">
						中国大陆
					</view>
				</view>
			</view>
			<view class="cu-form-group">
				<view class="title">验证码</view>
				<input placeholder="请输入验证码" name="code" type="number" maxlength="4"></input>
				<button class='cu-btn bg-green shadow' @tap="countDown" :disabled="this.countNum<60 && this.countNum>0?true:false">
					<!-- <span>{{this.$store.state.countNum<60 && this.$store.state.countNum>0?'倒计时'+this.$store.state.countNum:'验证码'}}</span> -->
					<span>{{this.countNum<60 && this.countNum>0?this.countNum+'s':'验证码'}}</span>
				</button>
			</view>
			<view>
				<button form-type="submit">登录</button>
			</view>
		</form>

将接收的信息上传到后端验证

this.$http.post('/authentication/mobile', {}, {
						params: {
							mobile: params.phoneNumbers,
							code: params.code
						}
					})

详细参考项目地址里面的源码

 

第三部分为2种情况.

1.发送手机验证码的api

controller代码

@GetMapping("/send/{phoneNumbers}")
    public String code(@PathVariable("phoneNumbers") String phoneNumbers){
        //调用发送方法
        //如果验证码存在 存在就是非过期
        String code=(String)redisTemplate.opsForValue().get(phoneNumbers);
        if (!StringUtils.isEmpty(code)){
            return phoneNumbers+":"+code+"已经存在,还没过期";
        }
        //如果不存在
        code=String.valueOf(new Random().nextLong()).substring(1,5);
        HashMap<String, Object> param=new HashMap<>();
        param.put("code",code);

        //如果发送成功,存手机验证码
        boolean isSend=sendSms.send(phoneNumbers,"SMS_189712947",param);
        if (isSend){
            redisTemplate.opsForValue().set(phoneNumbers,code,500, TimeUnit.MINUTES);
            return phoneNumbers+":"+code+"发送成功!";
        }else {
            return "发送失败";
        }
    }

service
public boolean send(String phoneNum, String templateCode, Map<String, Object> code) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "你的阿里云短信key", "密码");
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");//不要改
        request.setVersion("2017-05-25");//不要改
        request.setAction("SendSms");

        //自定义的参数(手机号,验证码,签名,模版)
        request.putQueryParameter("PhoneNumbers", phoneNum);//手机号码
        request.putQueryParameter("SignName","你的签名名字");
        request.putQueryParameter("TemplateCode",templateCode);//模版代码
        //构建短信验证码
//        HashMap hashMap=new HashMap();
//        hashMap.put("code",2233);//code里面的就是你发送给用户手机的验证码
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(code));

        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            return  response.getHttpResponse().isSuccess();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

2.处理上传的手机相关信息

如果是普通的boot项目,没有权限之类的控制.单独起一个接口进行参数接收,从redis根据手机号拿出验证码进行对比验证即可

如果是基于springsecuity搭建起的boot项目,因为默认只接收用户名,不能满足需求,可以通过自定义过滤器实现(完整代码参考项目地址里面)

//1.1写一个拦截器
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    protected SmsCodeAuthenticationFilter(String defaultFilterProcessesUrl) {
        //验证成功后
        super(defaultFilterProcessesUrl);
    }

    protected SmsCodeAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
        super(requiresAuthenticationRequestMatcher);
    }
    //判断手机和验证码是否正常
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        System.out.println(request.getParameter("mobile"));
        System.out.println(request.getParameter("code"));
        System.out.println("1.--------请求手机登录------判断手机和验证码是否正常");
        //如果方法的类型不是POST,拒绝处理
        if (!request.getMethod().equals("POST")) {
            System.out.println("方法不是POST,手机登录结束");
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        RedisTemplate redisTemplate=
                (RedisTemplate) SpringContextUtil.getBean("redisTemplate");
        ObjectMapper objectMapper=SpringContextUtil.getBean(ObjectMapper.class);

        String mobile = request.getParameter("mobile");
        Object code=redisTemplate.opsForValue().get(mobile);
        httpServletResponse.setCharacterEncoding("utf-8");
        System.out.println("2.当前请求登录的手机号为"+mobile);
        /**
         * 情况:
         * 1.存在 当前处于用手机验证码登录的状态
         * 2.不存在 验证码过期或者还没发送验证码
         */
        //验证码不存在
        if (StringUtils.isEmpty(code)){
            System.out.println("验证码过期或未发送");
            CommonResult commonResult=new CommonResult(406,"验证码未发送或验证码已过期");
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(commonResult));
            return null;
        }
        //验证码存在
        String pcode=request.getParameter("code");
        System.out.println("3.判断验证码是否正确[前端传入的验证码"+pcode+"],[redis数据库存储的验证码"+code+"]");
        if (!code.equals(pcode)) {
            System.out.println("验证码错误");
            CommonResult commonResult=new CommonResult(407,"验证码错误");
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(commonResult));
            return null;
        }
        System.out.println("4.验证码和手机都正常,颁发token和返回用户信息");
        // 封装令牌
        SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile,pcode);
        setDetails(request, authRequest);
        // 开始认证
        //调用SmsCodeAuthenticationProvider的authenticate
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

}
//1.2配置自定义的信息存储类
package com.example.authenticationserver.authentication;

import com.example.authenticationserver.pojo.MysqlUser;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

/**
 * @author qm
 * @date 2020/5/15 13:10
 */
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 1L;

    /** 身份 */
    private final Object principal;
    /** 验证码 */
    private String code;
    /** 权限 */
    private String role;
    /** 别名 */
    private String nickName;
    /** 用户信息 */
    private MysqlUser mysqlUser;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public SmsCodeAuthenticationToken(
            Collection<? extends GrantedAuthority> authorities,MysqlUser mysqlUser
            ,Object principal,String nickName) {
        super(authorities);
        this.principal = principal;
        this.mysqlUser=mysqlUser;
        this.nickName = nickName;
    }
    public void clear(){
        this.mysqlUser=null;
    }

    public SmsCodeAuthenticationToken(Object mobile, String code) {
        super(null);
        this.code=code;
        this.principal = mobile;
        setAuthenticated(false);
    }

    public SmsCodeAuthenticationToken(Object principal, String code,Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.code=code;
        this.principal = principal;
        // must use super, as we override
        super.setAuthenticated(true);
    }
    public SmsCodeAuthenticationToken(Object principal,Collection<? extends GrantedAuthority> authorities,MysqlUser mysqlUser) {
        super(authorities);
        this.principal = principal;
        // must use super, as we override
        super.setAuthenticated(true);
        this.mysqlUser=mysqlUser;
    }
    public String getCode() {
        return code;
    }

    public MysqlUser getMysqlUser() {
        return mysqlUser;
    }

    @Override
    public Object getPrincipal() {
        return this.principal;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }

        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
    }

    @Override
    public Object getCredentials() {
        return null;
    }


}
//1.3书写过滤器配置信息
@Component
public class SmsCodeAuthenticationSecurityConfig
        extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    @Qualifier("myAuthenticationSuccessHandler")
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;



    @Override
    public void configure(HttpSecurity http) throws Exception {
        SmsCodeAuthenticationFilter smsCodeAuthenticationFilter =
                new SmsCodeAuthenticationFilter("/authentication/mobile");
        smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);

        SmsCodeAuthenticationProvider provider = new SmsCodeAuthenticationProvider();
        // 将SmsCodeAuthenticationFilter放到过滤器链的UsernamePasswordAuthenticationFilter的后面
        http
                .authenticationProvider(provider)
                .addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }
}
//1.4配置验证器,配置如何验证
//如何验证
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 验证码和手机都没问题,开始用户操作
     *
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MysqlUserDao mysqlUserDao= SpringContextUtil.getBean(MysqlUserDao.class);
        System.out.println("5.--------用户验证---判断该用户是否存在于数据库,不存在则创建");
        String mobile=(String) authentication.getPrincipal();
        MysqlUser user = mysqlUserDao.findOne(mobile);
        if (user==null){
            System.out.println("6.用户未注册,用户注册开始........");
            MysqlUser mysqlUser = new MysqlUser();
            mysqlUser.setGender(0);
            mysqlUser.setNickName(mobile);
            mysqlUser.setRole("user");
            mysqlUser.setAccount(mobile);
            mysqlUser.setMobile(mobile);
            mysqlUser.setAvatarUrl("http://qzapp.qlogo.cn/qzapp/1104455702/80B727209F00D44C35166EB2D6B21086/30");
            mysqlUser.setPassword(new BCryptPasswordEncoder().encode("123"));
            int i = mysqlUserDao.add(mysqlUser);
            System.out.println("注册结果"+i);
            user = mysqlUserDao.findOne(mobile);
        }else {
            System.out.println("6.用户存在");
        }
//        //验证正常,封装用户信息返回
//        Collection<GrantedAuthority> authorities=new ArrayList<>();
//        authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
        //设置权限
        Collection<GrantedAuthority> authorities=new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(user.getRole()));
        //其他信息
        SmsCodeAuthenticationToken authenticationResult =
                new SmsCodeAuthenticationToken(user.getAccount(),authorities,user);
        authenticationResult.setDetails(authenticationToken.getDetails());

        return authenticationResult;
    }
    //模拟手机号进行验证
    private void simulationVerification(String number, String pcode){
        //当收到验证码8888和手机号13005630595才算成功
      final String phone="13005630595";
      final String code="8888";

      if (!phone.equals(number)){
          throw new InternalAuthenticationServiceException("手机号不存在");
      }
      if (!code.equals(pcode)) {
          //判断验证码是否想等
          throw new InternalAuthenticationServiceException("验证码错误");
      }

    }
    //
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
//1.5到安全框架的配置里面进行配置更新
@Autowired
private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
@Override
    protected void configure(HttpSecurity http) throws Exception {
        //引入短信拦截器配置
        http
                .apply(smsCodeAuthenticationSecurityConfig);
//1.6编写登录成功,如何处理(生成token和获取用户信息进行返回)
@Slf4j
@Component
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Autowired
    private ClientDetailsService clientDetailsService;
    //
    @Qualifier("defaultAuthorizationServerTokenServices")
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private MysqlUserDao mysqlUserDao;

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException, IOException {

        SmsCodeAuthenticationToken smsCodeAuthenticationToken=(SmsCodeAuthenticationToken)authentication;
        MysqlUser user = ((SmsCodeAuthenticationToken) authentication).getMysqlUser();
        smsCodeAuthenticationToken.clear();
        System.out.println("7.登录完成,准备返回token和用户信息");
//        Collection<GrantedAuthority> authorities=new ArrayList<>();
//        //设置权限
//        authorities.add(new SimpleGrantedAuthority("admin"));
//        SmsCodeAuthenticationToken smsCodeAuthenticationToken1=
//                new SmsCodeAuthenticationToken(authorities,"13005630595","ROLE_ADMIN","曲线");
//        System.out.println(smsCodeAuthenticationToken.getCode());
//        System.out.println(smsCodeAuthenticationToken.getPrincipal());
//        System.out.println(smsCodeAuthenticationToken);
//        System.out.println(authentication);
//        System.out.println("7.准备生成token");
        OAuth2AccessToken token = createToken(authentication);
        System.out.println("7.1:user信息"+user);
        System.out.println("7.2:token信息"+token);
        //封装用户信息和token信息返回
        Map map=new HashMap<>();
        map.put("code",200);
        map.put("authResult",token);
        //map.put("userInfo",mysqlUserDao.findOne((String) authentication.getPrincipal()));
        map.put("userInfo",user);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(map));
    }
    public OAuth2AccessToken createToken(Authentication authentication){
        ClientDetails clientDetails=clientDetailsService.loadClientByClientId("myapp_id");
        TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), "myapp_id",clientDetailsService.loadClientByClientId("myapp_id").getScope(), "custom");
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
        OAuth2AccessToken accessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
        return accessToken;
    }
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值