《果然新鲜》电商项目(25)- 会员唯一登录

网友投稿 263 2022-09-24

《果然新鲜》电商项目(25)- 会员唯一登录

文章目录

​​引言​​​​1.什么是唯一登录?​​​​2.会员唯一登录的实现思路​​​​3. 功能实现​​

​​3.1 数据库设计​​​​3.2 代码实现​​

​​3.2.1 用户登录​​​​3.2.2 获取用户信息​​

​​4. 测试​​

​​4.1 三端唯一登录测试​​​​4.2 根据token获取用户信息​​

​​5.总结​​

引言

在上一节​​《果然新鲜》电商项目(24)- 日志打印​​,主要讲解slf4j日志框架的基本使用方法。

本文主要简单的讲解会员服务如何实现唯一登录。

1.什么是唯一登录?

2.会员唯一登录的实现思路

3. 功能实现

3.1 数据库设计

在会员数据库(guoranxinxian-member)创建表,脚本如下:

CREATE TABLE `user_token` ( `id` int(11) NOT NULL AUTO_INCREMENT, `token` varchar(255) DEFAULT NULL, `login_type` varchar(255) CHARACTER SET utf8 DEFAULT NULL, `device_infor` varchar(255) DEFAULT NULL, `is_availability` int(2) DEFAULT NULL, `user_id` int(11) DEFAULT NULL, `create_time` date DEFAULT NULL, `update_time` date DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2

package com.guoranxinxian.entity;import lombok.Data;@Datapublic class UserTokenDo { /** * id */ private Long id; /** * 用户token */ private String token; /** * 登陆类型 */ private String loginType; /** * 设备信息 */ private String deviceInfor; /** * 用户userId */ private Long userId;}

package com.guoranxinxian.mapper;import com.guoranxinxian.entity.UserTokenDo;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.annotations.Update;/** * description: 用户TokenMapper */public interface UserTokenMapper { /** * 根据userid+loginType +is_availability=0 进行查询 * * @param userId * @param loginType * @return */ @Select("SELECT id as id ,token as token ,login_type as LoginType, device_infor as deviceInfor ,is_availability as isAvailability,user_id as userId" + "" + "" + " , create_time as createTime,update_time as updateTime FROM user_token WHERE user_id=#{userId} AND login_type=#{loginType} and is_availability ='0'; ") UserTokenDo selectByUserIdAndLoginType(@Param("userId") Long userId, @Param("loginType") String loginType); /** * 根据userId+loginType token的状态修改为不可用 * * @param token * @return */ @Update(" update user_token set is_availability ='1', update_time=now() where token=#{token}") int updateTokenAvailability(@Param("token") String token); /** * token记录表中插入一条记录 * * @param userTokenDo * @return */ @Insert("INSERT INTO `user_token` VALUES (null, #{token},#{loginType}, #{deviceInfor}, 0, #{userId} ,now(),null ); ") int insertUserToken(UserTokenDo userTokenDo);}

3.2 代码实现

3.2.1 用户登录

1.定义token生成工具类:

package com.guoranxinxian.util;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.UUID;/** * description: Token生成工具类 */@Componentpublic class GenerateToken { @Autowired private RedisUtil redisUtil; /** * 生成令牌 * * @param keyPrefix 令牌key前缀 * @param redisValue redis存放的值 * @return 返回token */ public String createToken(String keyPrefix, String redisValue) { return createToken(keyPrefix, redisValue, null); } /** * 生成令牌 * * @param keyPrefix 令牌key前缀 * @param redisValue redis存放的值 * @param time 有效期 * @return 返回token */ public String createToken(String keyPrefix, String redisValue, Long time) { if (StringUtils.isEmpty(redisValue)) { new Exception("redisValue Not nul"); } String token = keyPrefix + UUID.randomUUID().toString().replace("-", ""); redisUtil.setString(token, redisValue, time); return token; } /** * 根据token获取redis中的value值 * * @param token * @return */ public String getToken(String token) { if (StringUtils.isEmpty(token)) { return null; } String value = redisUtil.getString(token); return value; } /** * 移除token * * @param token * @return */ public Boolean removeToken(String token) { if (StringUtils.isEmpty(token)) { return null; } return redisUtil.delKey(token); }}

2.新增常量定义(其实不应该都只写到通用的​​Constants​​​,应该每个微服务对应一个​​Constants​​​。还有不会放到​​Apollo​​里,因为这些常量不经常变):

// token String MEMBER_TOKEN_KEYPREFIX = "guoranxinxian.member.login"; // 安卓的登陆类型 String MEMBER_LOGIN_TYPE_ANDROID = "Android"; // IOS的登陆类型 String MEMBER_LOGIN_TYPE_IOS = "IOS"; // PC的登陆类型 String MEMBER_LOGIN_TYPE_PC = "PC"; // 登陆超时时间 有效期 90天 Long MEMBRE_LOGIN_TOKEN_TIME = 77776000L;

3.用户登录接口:

UserLoginInDTO

package com.guoranxinxian.member.dto.input;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;/** * description: 用户登录请求参数 */@Data@ApiModel(value = "用户登录参数")public class UserLoginInDTO { /** * 手机号码 */ @ApiModelProperty(value = "手机号码") private String mobile; /** * 密码 */ @ApiModelProperty(value = "密码") private String password; /** * 登陆类型 PC、Android 、IOS */ @ApiModelProperty(value = "登陆类型") private String loginType; /** * 设备信息 */ @ApiModelProperty(value = "设备信息") private String deviceInfor;}

package com.guoranxinxian.service;import com.alibaba.fastjson.JSONObject;import com.guoranxinxian.api.BaseResponse;import com.guoranxinxian.member.dto.input.UserLoginInDTO;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;/** * description: 用户登录接口服务 * create by: YangLinWei * create time: 2020/3/3 4:35 下午 */@Api(tags = "用户登录服务接口")public interface MemberLoginService { /** * 用户登录接口 * * @param userLoginInDTO * @return */ @PostMapping("/login") @ApiOperation(value = "会员用户登陆信息接口") BaseResponse login(@RequestBody UserLoginInDTO userLoginInDTO);}

4.用户登录接口实现:

package com.guoranxinxian.mapper;import com.guoranxinxian.entity.UserDo;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;/** * description: 用户mapper */public interface UserMapper { @Insert("INSERT INTO `user` VALUES (null,#{mobile}, #{email}, #{password}, #{userName}, null, null, null, '1', null, null, null);") int register(UserDo userEntity); @Select("SELECT * FROM user WHERE MOBILE=#{mobile};") UserDo existMobile(@Param("mobile") String mobile); @Select("SELECT USER_ID AS USERID ,MOBILE AS MOBILE,EMAIL AS EMAIL,PASSWORD AS PASSWORD, USER_NAME AS USER_NAME ,SEX AS SEX ,AGE AS AGE ,CREATE_TIME AS CREATETIME,IS_AVALIBLE AS ISAVALIBLE,PIC_IMG AS PICIMG,QQ_OPENID AS QQOPENID,WX_OPENID AS WXOPENID " + " FROM user WHERE MOBILE=#{mobile} and password=#{password};") UserDo login(@Param("mobile") String mobile, @Param("password") String password); @Select("SELECT USER_ID AS USERID ,MOBILE AS MOBILE,EMAIL AS EMAIL,PASSWORD AS PASSWORD, USER_NAME AS userName ,SEX AS SEX ,AGE AS AGE ,CREATE_TIME AS CREATETIME,IS_AVALIBLE AS ISAVALIBLE,PIC_IMG AS PICIMG,QQ_OPENID AS QQOPENID,WX_OPENID AS WXOPENID" + " FROM user WHERE user_Id=#{userId}") UserDo findByUserId(@Param("userId") Long userId);}

package com.guoranxinxian.impl;import com.alibaba.fastjson.JSONObject;import com.guoranxinxian.api.BaseResponse;import com.guoranxinxian.constants.Constants;import com.guoranxinxian.entity.BaseApiService;import com.guoranxinxian.entity.UserDo;import com.guoranxinxian.entity.UserTokenDo;import com.guoranxinxian.mapper.UserMapper;import com.guoranxinxian.mapper.UserTokenMapper;import com.guoranxinxian.member.dto.input.UserLoginInDTO;import com.guoranxinxian.service.MemberLoginService;import com.guoranxinxian.util.GenerateToken;import com.guoranxinxian.util.MD5Util;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class MemberLoginServiceImpl extends BaseApiService implements MemberLoginService { @Autowired private UserMapper userMapper; @Autowired private GenerateToken generateToken; @Autowired private UserTokenMapper userTokenMapper; @Override public BaseResponse login(@RequestBody UserLoginInDTO userLoginInpDTO) { // 1.验证参数 String mobile = userLoginInpDTO.getMobile(); if (StringUtils.isEmpty(mobile)) { return setResultError("手机号码不能为空!"); } String password = userLoginInpDTO.getPassword(); if (StringUtils.isEmpty(password)) { return setResultError("密码不能为空!"); } // 判断登陆类型 String loginType = userLoginInpDTO.getLoginType(); if (StringUtils.isEmpty(loginType)) { return setResultError("登陆类型不能为空!"); } // 目的是限制范围 if (!(loginType.equals(Constants.MEMBER_LOGIN_TYPE_ANDROID) || loginType.equals(Constants.MEMBER_LOGIN_TYPE_IOS) || loginType.equals(Constants.MEMBER_LOGIN_TYPE_PC))) { return setResultError("登陆类型出现错误!"); } // 设备信息 String deviceInfor = userLoginInpDTO.getDeviceInfor(); if (StringUtils.isEmpty(deviceInfor)) { return setResultError("设备信息不能为空!"); } // 2.对登陆密码实现加密 String newPassWord = MD5Util.MD5(password); // 3.使用手机号码+密码查询数据库 ,判断用户是否存在 UserDo userDo = userMapper.login(mobile, newPassWord); if (userDo == null) { return setResultError("用户名称或者密码错误!"); } // 用户登陆Token Session 区别 // 用户每一个端登陆成功之后,会对应生成一个token令牌(临时且唯一)存放在redis中作为rediskey value userid // 4.获取userid Long userId = userDo.getUserId(); // 5.根据userId+loginType 查询当前登陆类型账号之前是否有登陆过,如果登陆过 清除之前redistoken UserTokenDo userTokenDo = userTokenMapper.selectByUserIdAndLoginType(userId, loginType); if (userTokenDo != null) { // 如果登陆过 清除之前redistoken String token = userTokenDo.getToken(); Boolean isremoveToken = generateToken.removeToken(token); if (isremoveToken) { // 把该token的状态改为1 userTokenMapper.updateTokenAvailability(token); } } // .生成对应用户令牌存放在redis中 String keyPrefix = Constants.MEMBER_TOKEN_KEYPREFIX + loginType; String newToken = generateToken.createToken(keyPrefix, userId + ""); // 1.插入新的token UserTokenDo userToken = new UserTokenDo(); userToken.setUserId(userId); userToken.setLoginType(userLoginInpDTO.getLoginType()); userToken.setToken(newToken); userToken.setDeviceInfor(deviceInfor); userTokenMapper.insertUserToken(userToken); JSONObject data = new JSONObject(); data.put("token", newToken); return setResultSuccess(data); }}

3.2.2 获取用户信息

1.新增获取用户信息接口:

/** * 根据token查询用户信息 * * @param token * @return */ @GetMapping("/getUserInfo") @ApiOperation(value = "/getUserInfo") BaseResponse getInfo(@RequestParam("token") String token);

2.实现接口:

@Select("SELECT id as id ,token as token ,login_type as LoginType, device_infor as deviceInfor ,is_availability as isAvailability,user_id as userId" + "" + "" + " , create_time as createTime,update_time as updateTime FROM user_token WHERE token=#{token} and is_availability ='0'; ") UserTokenDo selectByToken(String token);

@Overridepublic BaseResponse getInfo(String token) { UserTokenDo userTokenDo = userTokenMapper.selectByToken(token); if(userTokenDo == null){ return setResultError("该用户没有登录!"); } UserDo userDo = userMapper.findByUserId(userTokenDo.getUserId()); if (userDo == null) { return setResultError("用户不存在!"); } // 下节课将 转换代码放入在BaseApiService return setResultSuccess(BeanUtils.doToDto(userDo, UserOutDTO.class));}

4. 测试

4.1 三端唯一登录测试

4.2 根据token获取用户信息

5.总结

本文主要讲解会员使用​​Android​​​、​​IOS​​​和​​PC​​来实现唯一登录,并通过token来获取用户信息。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:js array数组拼接 push() concat() 的方法效率对比,差10倍
下一篇:曹骏给自己颜值打90分,想和吴京合作,蓝盈莹曾鼓励其参加综艺!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~