標題:登錄流程

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;

}

}