標題:登錄流程
1、用户登錄:
1.1、判斷用户名、密碼、type(區別是員工登錄還是用户登錄)是否為空
1.2、判斷用户名是否存在,不存在 拋出:用户名不存在,請註冊
1.3用户名存在,判斷密碼是否一致
1.3.1、由於數據庫中密碼是通過MD5進行加密過,而前端傳入過來的密碼沒有加密,判斷密碼是否的話,要先把其前端傳入的密碼進行MD5加密後再判斷。
1.3.2、如果密碼不等,拋出:密碼錯誤
1.4、把用户信息存入redis中,設置過期 時間為30分鐘
存入redis後設置用户名和密碼為空串,安全些。
2、微信登錄
2.1、在登陸頁面上點擊微信登錄按鈕,頁面向微信第三方發送請求,微信第三方向頁面返回一個二維碼,用户掃碼授權後,頁面獲取微信用户信息
2.2、微信收到確認授權後,生成一個code(授權碼),從請求欄中獲取code
2.3、後台寫好接口,將code傳給後台,交給service層處理
2.4、判斷code是否為空
2.5、通過code、、appid、 SECRET獲取令牌(token),獲取token和oppenid
2.5.1、判斷opedid是否為空,查詢wxuser表,如果oppedid不為空且userid也不為空,説明以前登陸過,直接免密登錄
2.5.2、 如果為空,需要讓用户綁定個人用户信息
返回token+openId 前端幫我們跳轉到綁定頁面
3、微信綁定流程
3.1、在callback.html頁面的鈎子函數中
3.2、接收微信登錄流程的返回值:
AjaxResult {success:false,resultObj:"?token=asdfaf$openId=136462315546"}
3.3、跳轉到binder.html頁面
location.href=“binder.html”+resultObj;
3.4、binder.html頁面解析地址欄參數並且接收用户輸入的參數
3.5、發起微信綁定流程
phone verifyCode token openId
3.6、後端接收參數交給service處理
3.7、service業務流
(1)校驗
1.空校驗
2.判斷驗證碼
(2)判斷phone是否被註冊 user
1.如果註冊了,那麼我們可以直接綁定微信用户了
2.如果沒有註冊過,生成t_user + t_loginInfo
(3)通過 token+openId 查詢微信信息 wxuser
生成t_wxuser
(4)綁定user和wxuser
(5)免密登錄
代碼如下:
package cn.lishaoqiang.user.service.impl;
import cn.lishaoqiang.basic.exception.MyExceeption;
import cn.lishaoqiang.basic.util.AjaxResult;
import cn.lishaoqiang.basic.util.HttpClientUtils;
import cn.lishaoqiang.basic.util.MD5Utils;
import cn.lishaoqiang.basic.util.StrUtils;
import cn.lishaoqiang.user.constant.WxConstants;
import cn.lishaoqiang.user.domain.LoginInfo;
import cn.lishaoqiang.user.domain.User;
import cn.lishaoqiang.user.domain.WxUser;
import cn.lishaoqiang.user.dto.LoginDto;
import cn.lishaoqiang.user.dto.UserDto;
import cn.lishaoqiang.user.mapper.LoginInfoMapper;
import cn.lishaoqiang.user.mapper.UserMapper;
import cn.lishaoqiang.user.mapper.WxUserMapper;
import cn.lishaoqiang.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class LoginServiceImpl implements ILoginService{@Autowired
private RedisTemplate redisTemplate;
@Autowired
private LoginInfoMapper loginInfoMapper;
@Autowired
private WxUserMapper wxUserMapper;
@Autowired
private UserMapper userMapper;
//用户登錄
@Override
public Map<String, Object> account(LoginDto loginDto) {
//1判斷用户名、密碼、type是否為空
if(StringUtils.isEmpty(loginDto.getUsername())
|| StringUtils.isEmpty(loginDto.getPassword())
|| StringUtils.isEmpty(loginDto.getType())){
throw new MyExceeption("參數不能為空");
}
//2判斷用户名是否存在
LoginInfo loginInfo = loginInfoMapper.loadByLoginDto(loginDto);
if(loginInfo==null){ //用户名不存在
throw new MyExceeption("用户不存在");
}
//3.用户名存在判斷密碼是否一致
//獲取當前的鹽值,通過鹽值和密碼進行MD5加密 ,再和數據庫中的密碼進行比較
String salt = loginInfo.getSalt();
String password = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
String dbPassword = loginInfo.getPassword();
if(!password.equals(dbPassword)){
throw new MyExceeption("密碼錯誤");
}
//4.吧用户信息存入redis中 key:token
//獲取token
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
Map<String, Object> map = new HashMap<>();
map.put("token", token);
//設置用户名和密碼為空,如果不設置的話會顯示在頁面的請求中,不安全
loginInfo.setSalt("");
loginInfo.setPassword("");
map.put("loginInfo", loginInfo); //loginInfo是對象,存對象需要 序列化
return map;
}
//微信登錄
@Override
public AjaxResult wechat(Map<String, String> map) {
String code = map.get("code");
if(StringUtils.isEmpty(code)){
throw new MyExceeption("系統異常");
}
//通過code。appid SECRET獲取令牌(token)
String url = WxConstants.GET_TOKEN_URL
.replace("APPID", WxConstants.APPID)
.replace("SECRET", WxConstants.SECRET)
.replace("CODE", code);
String obj = HttpClientUtils.httpGet(url);
//把字符串轉成json對象
JSONObject jsonObject = JSONObject.parseObject(obj);
//獲取token和openid
String token = jsonObject.getString("access_token");
String openid = jsonObject.getString("openid");
//判斷openid是否為空 通過查詢wxuser表查詢
WxUser wxUser = wxUserMapper.loadByOpenId(openid);
//拼接參數
String param = "?token="+token+"&openid="+openid;
//如果用户不為空並且userid不為空,説明登陸過,直接免密登錄
if(wxUser!=null && wxUser.getUser_id()!=null){
//通過wxUser查詢loginInfo的信息
LoginInfo loginInfo = loginInfoMapper.loadByUserid(wxUser.getUser_id());
//把token存入redis中
String uToken = UUID.randomUUID().toString();
//System.out.println(uToken);
redisTemplate.opsForValue().set(uToken, loginInfo, 30, TimeUnit.MINUTES);
Map<String, Object> rMap = new HashMap<>();
rMap.put("token", uToken);
//設置用户名和密碼為空,如果不設置的話會顯示在頁面的請求中,不安全
loginInfo.setSalt("");
loginInfo.setPassword("");
rMap.put("loginInfo",loginInfo); //loginInfo是對象,存對象需要 序列化
return AjaxResult.my().setResultObj(rMap);
}
return AjaxResult.my().setSuccess(false).setResultObj(param);
}
/*
*
* 微信綁定登錄
*/
@Override
public Map<String, Object> binder(Map<String, String> map) {
String phone = map.get("phone");
String verifyCode = map.get("verifyCode");
String accessToken = map.get("accessToken");
String openId = map.get("openId");
//1.非空校驗
if(StringUtils.isEmpty(phone)||
StringUtils.isEmpty(verifyCode)){
throw new MyExceeption("系統異常");
}
//3.判斷phone是否註冊過
User user = userMapper.loadByPhone(phone);
User userTemp = null;
LoginInfo loginInfo = null;
if(user != null){ //説明註冊過 有user,loginInfo了
//獲取用户信息,保存在wxuser表中
userTemp = user;
loginInfo = loginInfoMapper.loadByUserid(userTemp.getId());
}else{ //如果沒有註冊,重新保存loginInfo,user,wxuser三張表
userTemp = initUser(phone);
loginInfo = initLoginInfo(userTemp);
//把user和loginInfo保存到wxuser中
loginInfo.setType(1);
loginInfoMapper.save(loginInfo);
//把loginInfo_id保存到user中
userTemp.setLogininfo_id(loginInfo.getId());
userMapper.save(userTemp);
}
String obj = HttpClientUtils.httpGet(WxConstants.GET_USER_URL
.replace("ACCESS_TOKEN", accessToken)
.replace("OPENID", openId));
WxUser wxUser = initWxuser(obj);
//綁定
wxUser.setUser_id(userTemp.getId());
//保存wxuser中的信息
wxUserMapper.save(wxUser);
//把登錄信息存入redis裏面
//獲取token
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
Map<String, Object> map1 = new HashMap<>();
map1.put("token", token);
//設置用户名和密碼為空,如果不設置的話會顯示在頁面的請求中,不安全
loginInfo.setSalt("");
loginInfo.setPassword("");
map1.put("loginInfo", loginInfo); //loginInfo是對象,存對象需要 序列化
return map1;
}
//根據obj生成wxuser對象
private WxUser initWxuser(String obj) {
JSONObject jsonObject = JSONObject.parseObject(obj);
WxUser wxUser = new WxUser();
wxUser.setOpenid(jsonObject.getString("openid"));
wxUser.setNickname(jsonObject.getString("nickname"));
wxUser.setSex(jsonObject.getInteger("sex"));
wxUser.setAddress(null);
wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
wxUser.setUnionid(jsonObject.getString("unionid"));
return wxUser;
}
//根據user生成loginInfo對象
private LoginInfo initLoginInfo(User user) {
LoginInfo info = new LoginInfo();
BeanUtils.copyProperties(user,info); //按照同名原則拷貝屬性
return info;
}
//根據手機號生成user對象
private User initUser(String phone) {
User user = new User();
user.setUsername(phone);
user.setPhone(phone);
user.setEmail(null);
//給一個隨機密碼
String salt = UUID.randomUUID().toString();
String password = MD5Utils.encrypByMd5("1"+salt);
user.setPassword(password);
user.setSalt(salt);
user.setState(1);
user.setCreatetime(new Date());
return user;
}
}