实现手机登录(短信验证)

您所在的位置:网站首页 如何远程入侵别人手机不用验证码登陆微信 实现手机登录(短信验证)

实现手机登录(短信验证)

#实现手机登录(短信验证)| 来源: 网络整理| 查看: 265

这里写目录标题 登录需求登录实现添加用户基础类JWT生成token搭建service-msm模块

登录需求

1,登录采取弹出层的形式 2,登录方式: (1)手机号码+手机验证码 (2)微信扫描 3,无注册界面,第一次登录根据手机号判断系统是否存在,如果不存在则自动注册 4,微信扫描登录成功必须绑定手机号码,即:第一次扫描成功后绑定手机号,以后登录扫描直接登录成功 5,网关统一判断登录状态,如何需要登录,页面弹出登录层

登录实现

1,搭建service-user模块 1.1 搭建service-user模块 搭建过程参考service-hosp模块 1.2 修改配置 1、修改pom.xml

service com.atguigu 0.0.1-SNAPSHOT 4.0.0 service_user com.atguigu service_cmn_client 0.0.1-SNAPSHOT

2、添加配置文件application.properties

# 服务端口 server.port=8203 # 服务名 spring.application.name=service-user # 环境设置:dev、test、prod spring.profiles.active=dev # mysql数据库连接 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.44.165:3306/yygh_user?characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=root123 #返回json的全局时间格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8 # nacos服务地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #配置mapper xml文件的路径 mybatis-plus.mapper-locations=classpath:com/atguigu/yygh/user/mapper/xml/*.xml

1.3 启动类

@SpringBootApplication @ComponentScan(basePackages = "com.atguigu") @EnableDiscoveryClient @EnableFeignClients(basePackages = "com.atguigu") public class ServiceUserApplication { public static void main(String[] args) { SpringApplication.run(ServiceUserApplication.class, args); } }

1.4配置网关

#设置路由id spring.cloud.gateway.routes[2].id=service-user #设置路由的uri spring.cloud.gateway.routes[2].uri=lb://service-user #设置路由断言,代理servicerId为auth-service的/auth/路径 spring.cloud.gateway.routes[2].predicates= Path=/*/user/** 添加用户基础类

2.1 添加model 说明:由于实体对象没有逻辑,我们已经统一导入 com.atguigu.yygh.model.user.UserInfo 2.2 添加Mapper 1,添加com.atguigu.yygh.user.UserInfoMapper

import com.atguigu.yygh.model.user.UserInfo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface UserInfoMapper extends BaseMapper { }

2,添加UserInfoMapper.xml

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

2.3 添加service接口及实现类 1、添加com.atguigu.yygh.user.service.UserInfoService接口

public interface UserInfoService extends IService { }

2、添加com.atguigu.yygh.user.service.impl.UserInfoServiceImpl接口实现

@Service public class UserInfoServiceImpl extends ServiceImpl implements UserInfoService { }

2.4 添加controller 添加com.atguigu.yygh.user.api.UserInfoApiController类

@RestController @RequestMapping("/api/user") public class UserInfoApiController { @Autowired private UserInfoService userInfoService; }

3、登录api接口 3.1 添加service接口与实现 1、在UserInfoService类添加接口

//会员登录 Map login(LoginVo loginVo);

2,在UserInfoServiceImpl类实现接口

@Service public class UserInfoServiceImpl extends ServiceImpl implements UserInfoService { @Override public Map login(LoginVo loginVo) { String phone = loginVo.getPhone(); String code = loginVo.getCode(); //校验参数 if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)) { throw new YyghException(ResultCodeEnum.PARAM_ERROR); } //TODO 校验校验验证码 //手机号已被使用 QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("phone", phone); //获取会员 UserInfo userInfo = baseMapper.selectOne(queryWrapper); if(null == userInfo) { userInfo = new UserInfo(); userInfo.setName(""); userInfo.setPhone(phone); userInfo.setStatus(1); this.save(userInfo); } //校验是否被禁用 if(userInfo.getStatus() == 0) { throw new YyghException(ResultCodeEnum.LOGIN_DISABLED_ERROR); } //TODO 记录登录 //返回页面显示名称 Map map = new HashMap(); String name = userInfo.getName(); if(StringUtils.isEmpty(name)) { name = userInfo.getNickName(); } if(StringUtils.isEmpty(name)) { name = userInfo.getPhone(); } map.put("name", name); map.put("token", ""); return map; } }

说明: 1、验证码先注释,后续校验 2、登录成功生成token,后续讲解 3.2 添加controller接口 1、在UserInfoApiController类添加方法

@ApiOperation(value = "会员登录") @PostMapping("login") public Result login(@RequestBody LoginVo loginVo, HttpServletRequest request) { loginVo.setIp(IpUtil.getIpAddr(request)); Map info = userInfoService.login(loginVo); return Result.ok(info); }

2、添加IpUtil工具类

public class IpUtil { private static final String UNKNOWN = "unknown"; private static final String LOCALHOST = "127.0.0.1"; private static final String SEPARATOR = ","; public static String getIpAddr(HttpServletRequest request) { System.out.println(request); String ipAddress; try { ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (LOCALHOST.equals(ipAddress)) { InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress = inet.getHostAddress(); } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 // "***.***.***.***".length() if (ipAddress != null && ipAddress.length() >15) { if (ipAddress.indexOf(SEPARATOR) >0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } } catch (Exception e) { ipAddress = ""; } return ipAddress; } } JWT生成token

JWT工具 JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上

JWT最重要的作用就是对 token信息的防伪作用。

JWT的原理, 一个JWT由三个部分组成:公共部分、私有部分、签名部分。最后由这三者组合进行base64编码得到JWT。

1、公共部分 主要是该JWT的相关配置参数,比如签名的加密算法、格式类型、过期时间等等。 Key=ATGUIGU 2、私有部分 用户自定义的内容,根据实际需要真正要封装的信息。 userInfo{用户的Id,用户的昵称nickName} 3、签名部分 SaltiP: 当前服务器的Ip地址!{linux 中配置代理服务器的ip} 主要用户对JWT生成字符串的时候,进行加密{盐值} 最终组成 key+salt+userInfo token! base64编码,并不是加密,只是把明文信息变成了不可见的字符串。但是其实只要用一些工具就可以把base64编码解成明文,所以不要在JWT中放入涉及私密的信息。 5.2 集成JWT 1,在common-util模块pom.xml添加依赖

io.jsonwebtoken jjwt

版本已在yygh-parent父模块pom.xml添加 2,在common-util模块编写JwtHelper类

public class JwtHelper { private static long tokenExpiration = 24*60*60*1000; private static String tokenSignKey = "123456"; public static String createToken(Long userId, String userName) { String token = Jwts.builder() .setSubject("YYGH-USER") .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) .claim("userId", userId) .claim("userName", userName) .signWith(SignatureAlgorithm.HS512, tokenSignKey) .compressWith(CompressionCodecs.GZIP) .compact(); return token; } public static Long getUserId(String token) { if(StringUtils.isEmpty(token)) return null; Jws claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); Integer userId = (Integer)claims.get("userId"); return userId.longValue(); } public static String getUserName(String token) { if(StringUtils.isEmpty(token)) return ""; Jws claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); return (String)claims.get("userName"); } public static void main(String[] args) { String token = JwtHelper.createToken(1L, "55"); System.out.println(token); System.out.println(JwtHelper.getUserId(token)); System.out.println(JwtHelper.getUserName(token)); } }

说明:执行main方法测试 5.3 完善登录service接口 修改UserInfoServiceImpl类登录方法

public Map loginUser(LoginVo loginVo) { ………… //jwt生成token字符串 String token = JwtHelper.createToken(userInfo.getId(), name); map.put("token",token); return map; } 搭建service-msm模块

6.2.1 搭建service-msm模块 搭建过程参考service-hosp模块 6.2.2修改配置 1、修改pom.xml

com.aliyun aliyun-java-sdk-core

2、添加配置文件application.properties

# 服务端口 server.port=8204 # 服务名 spring.application.name=service-msm #返回json的全局时间格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8 spring.redis.host=192.168.44.165 spring.redis.port=6379 spring.redis.database= 0 spring.redis.timeout=1800000 spring.redis.lettuce.pool.max-active=20 spring.redis.lettuce.pool.max-wait=-1 #最大阻塞等待时间(负数表示没限制) spring.redis.lettuce.pool.max-idle=5 spring.redis.lettuce.pool.min-idle=0 # nacos服务地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 aliyun.sms.regionId=default aliyun.sms.accessKeyId=LT6I0Y5633pX89qC aliyun.sms.secret=jX8D04Dm12I3gGKj345FYSzu0fq8mT

6.2.3 启动类

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置 @EnableDiscoveryClient public class ServiceMsmApplication { public static void main(String[] args) { SpringApplication.run(ServiceMsmApplication.class, args); } }

6.2.4 配置网关

#设置路由id spring.cloud.gateway.routes[3].id=service-msm #设置路由的uri spring.cloud.gateway.routes[3].uri=lb://service-msm #设置路由断言,代理servicerId为auth-service的/auth/路径 spring.cloud.gateway.routes[3].predicates= Path=/*/msm/**

6.3封装注册短信验证码接口 6.3.1 添加配置类

@Component public class ConstantPropertiesUtils implements InitializingBean { @Value("${aliyun.sms.regionId}") private String regionId; @Value("${aliyun.sms.accessKeyId}") private String accessKeyId; @Value("${aliyun.sms.secret}") private String secret; public static String REGION_Id; public static String ACCESS_KEY_ID; public static String SECRECT; @Override public void afterPropertiesSet() throws Exception { REGION_Id=regionId; ACCESS_KEY_ID=accessKeyId; SECRECT=secret; } }

6.3.2 封装service接口和实现类

public interface MsmService { //发送手机验证码 boolean send(String phone, String code); } @Service public class MsmServiceImpl implements MsmService { @Override public boolean send(String phone, String code) { //判断手机号是否为空 if(StringUtils.isEmpty(phone)) { return false; } //整合阿里云短信服务 //设置相关参数 DefaultProfile profile = DefaultProfile. getProfile(ConstantPropertiesUtils.REGION_Id, ConstantPropertiesUtils.ACCESS_KEY_ID, ConstantPropertiesUtils.SECRECT); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); //request.setProtocol(ProtocolType.HTTPS); request.setMethod(MethodType.POST); request.setDomain("dysmsapi.aliyuncs.com"); request.setVersion("2017-05-25"); request.setAction("SendSms"); //手机号 request.putQueryParameter("PhoneNumbers", phone); //签名名称 request.putQueryParameter("SignName", "我的谷粒在线教育网站"); //模板code request.putQueryParameter("TemplateCode", "SMS_180051135"); //验证码 使用json格式 {"code":"123456"} Map param = new HashMap(); param.put("code",code); request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param)); //调用方法进行短信发送 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; } }

6.3.3 封装controller接口

@RestController @RequestMapping("/api/msm") public class MsmApiController { @Autowired private MsmService msmService; @Autowired private RedisTemplate redisTemplate; //发送手机验证码 @GetMapping("send/{phone}") public Result sendCode(@PathVariable String phone) { //从redis获取验证码,如果获取获取到,返回ok // key 手机号 value 验证码 String code = redisTemplate.opsForValue().get(phone); if(!StringUtils.isEmpty(code)) { return Result.ok(); } //如果从redis获取不到, // 生成验证码, code = RandomUtil.getSixBitRandom(); //调用service方法,通过整合短信服务进行发送 boolean isSend = msmService.send(phone,code); //生成验证码放到redis里面,设置有效时间 if(isSend) { redisTemplate.opsForValue().set(phone,code,2, TimeUnit.MINUTES); return Result.ok(); } else { return Result.fail().message("发送短信失败"); } } }

工具类

public class RandomUtil { private static final Random random = new Random(); private static final DecimalFormat fourdf = new DecimalFormat("0000"); private static final DecimalFormat sixdf = new DecimalFormat("000000"); public static String getFourBitRandom() { return fourdf.format(random.nextInt(10000)); } public static String getSixBitRandom() { return sixdf.format(random.nextInt(1000000)); } /** * 给定数组,抽取n个数据 * @param list * @param n * @return */ public static ArrayList getRandom(List list, int n) { Random random = new Random(); HashMap hashMap = new HashMap(); // 生成随机数字并存入HashMap for (int i = 0; i r.add(list.get((int) robjs[i])); System.out.print(list.get((int) robjs[i]) + "\t"); } System.out.print("\n"); return r; } }

6.3.4 完善登录service接口 修改UserInfoServiceImpl类登录方法,编写验证码校验

//校验校验验证码 String mobleCode = redisTemplate.opsForValue().get(phone); if(!code.equals(mobleCode)) { throw new YyghException(ResultCodeEnum.CODE_ERROR); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3