天天看點

微信網頁登入

第一:微信公衆号測試平台

http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

微信網頁登入

http://393.104.170.232/chainStore/userController/pcAuth.do

第二:

微信網頁登入
微信網頁登入

隻填ip位址,不要加http或https

第三:登入頁面加入

<script type="text/javascript" src="web/pages/js/qrcode.js"></script>

<button onclick="wechatLogin()">微信登入</button>

<input type="hidden" id="sessionId"/>

<div id="code"></div>

function checkLogin(){

console.log("checkLogin");

var i = 0;

var sessionId = $("#sessionId").val();

console.log("sessionId:"+sessionId);

if(sessionId!=""){

$.ajax({

url: "userController/polling.do",

type: "POST",

data:{sessionId:sessionId},

dataType:\'json\',

success: function (data) {

console.log(data);

if(data.status=="200"){

window.clearInterval(c);

//location.href = "/";

window.location = "web/main.jsp";

}else{

i++;

if(i>60){

window.clearInterval(c);

mini.alert("二維碼已失效!請重新整理二維碼。");

}

}

}

});

}

}

function wechatLogin(){

$.ajax({

url: "userController/wxLoginPage.do",

type: "post",

dataType:\'json\',

success: function (data) {

$("#sessionId").val(data.sessionId);

var qrcode = new QRCode(document.getElementById("code"), {

width : 200,//設定寬高

height : 200

});

qrcode.makeCode(data.uri);

c = setInterval(checkLogin,5000);//輪詢查詢

}

});

}

第四:controller層

//pc點選微信登入,生成登入二維碼

@ResponseBody

@RequestMapping("/wxLoginPage")

public Map<String,String> wxLoginPage(HttpServletRequest request) {

Map<String,String> map = new HashMap<String,String>();

try {

String sessionId = request.getSession().getId();

logger.info("sessionId:"+sessionId);

String uri = this.weChatAuthServiceImpl.getAuthorizationUrl("pc",sessionId);//設定redirect_uri和state=sessionId以及測試号資訊,傳回授權url

logger.info(uri);

map.put("sessionId", sessionId);

map.put("uri", uri);//用來前端生成二維碼

} catch (Exception e) {

e.printStackTrace();

}

return map;

}

//掃描二維碼授權成功,取到code,回調方法

@RequestMapping("/pcAuth")

@ResponseBody

public String pcCallback(String code,String state,HttpServletRequest request,HttpServletResponse response) throws Exception {

logger.info("code:"+code+" = state:"+state);

String result = weChatAuthServiceImpl.getAccessToken(code);//根據code擷取access_token和openId,不懂看微信文檔

JSONObject jsonObject = JSONObject.parseObject(result);

//String refresh_token = jsonObject.getString("refresh_token");

String access_token = jsonObject.getString("access_token");

String openId = jsonObject.getString("openId");

logger.info("------------授權成功----------------");

JSONObject infoJson = weChatAuthServiceImpl.getUserInfo(access_token,openId);//根據token和openId擷取微信使用者資訊,不懂看我上一篇文章開始分享的連結

if(infoJson!=null){

String nickname = infoJson.getString("nickName");

logger.info("-----nickname-----"+nickname);

logger.info("-----sessionId-----"+state);

infoJson.put("openId", openId);

//redisTemplate.opsForValue().set(state, infoJson, 10*60, TimeUnit.SECONDS);

this.userInfoService.saveWxUser(state,infoJson);

return "登入成功!";

}

return "登入失敗!";

}

//輪詢查詢key

@RequestMapping(value="/polling")

@ResponseBody

public Map<String, Object> polling(String sessionId,HttpServletRequest request,HttpServletResponse response){

Map<String, Object> resultMap = new LinkedHashMap<String, Object>();

String infoJsonstr = this.userInfoService.getWxUser(sessionId);

if(infoJsonstr!=null){

JSONObject infoJson = JSON.parseObject(infoJsonstr);

this.userInfoService.delWxUser(sessionId);

String openId = (String)infoJson.get("openId");

//根據openId判斷我們網站是否存在該使用者,資料庫使用者表會儲存使用者

SysUserInfo user = this.userInfoService.selectUserByWechat(openId);

if (user == null) {

String nickname = (String)infoJson.get("nickName");

String sex = (String)infoJson.get("sex");

SysUserInfo newuser = new SysUserInfo();

newuser.setCharSex(sex.equals("男")?"1":"0");

newuser.setCharUserName(openId);

newuser.setCharPassWord(openId);

newuser.setCharRealName(nickname);

String i = (String) userInfoService.save(newuser);//新增使用者

if(i.length()<1){

resultMap.put("status", 500);

resultMap.put("message", "登入失敗:");

resultMap.put("success", false);

resultMap.put("msg", "登入失敗!");

return resultMap;

}

}

//登入操作

try {

UsernamePasswordToken token = new UsernamePasswordToken(openId, openId);//這裡是用shiro登入,反正該openId已經微信掃碼驗證

token.setRememberMe(true);

Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);

if(currentUser.isAuthenticated()){

resultMap.put("status", 200);

resultMap.put("message", "登入成功");

resultMap.put("success", true);

resultMap.put("msg", "登入成功");

}else{

resultMap.put("status", 500);

resultMap.put("message", "登入失敗");

resultMap.put("success", false);

resultMap.put("msg", "登入失敗");

}

//更新使用者最後登入時間

/*Subject currentUser = SecurityUtils.getSubject();

SysUserInfo luser = (SysUserInfo) currentUser.getPrincipal();

SysUserInfo user1 = this.userInfoService.getById(luser.getId());

Map<String,String> map= this.userInfoService.getUserAgent(request);

user1.setCharLastIp(luser.getCharCurrIp());

user1.setCharCurrIp(request.getRemoteAddr());

user1.setDateModifyTime(new Date());

user1.setDateLoginTime(new Date());

user1.setCharBrowserType(map.get("type"));

user1.setCharBrowserVersion(map.get("version"));

user1.setDateLoginTime(new Date());

this.userInfoService.update(user1);*///更新使用者方法

} catch (Exception e) {

resultMap.put("message", "未知系統錯誤:" + e.getMessage());

}

return resultMap;

}else{//not has key

resultMap.put("status", 0);

return resultMap;

}

/*if(redisTemplate.hasKey(sessionId)){

JSONObject infoJson = (JSONObject)redisTemplate.opsForValue().get(sessionId);

redisTemplate.opsForValue().getOperations().delete(sessionId);

String openId = (String)infoJson.get("openId");

//根據openId判斷我們網站是否存在該使用者,資料庫使用者表會儲存使用者

User user = userService.selectUserByWechat(openId);

if (user == null) {

String nickname = (String)infoJson.get("nickName");

String sex = (String)infoJson.get("sex");

User newuser = new User();

newuser.setSex(sex);

newuser.setWechat(openId);

newuser.setNickname(nickname);

int i = userService.insertUser(newuser);//新增使用者

if(i<1){

resultMap.put("status", 500);

resultMap.put("message", "登入失敗:");

return resultMap;

}

}

//登入操作

try {

UsernamePasswordToken token = new UsernamePasswordToken(openId, openId);//這裡是用shiro登入,反正該openId已經微信掃碼驗證

SecurityUtils.getSubject().login(token);

resultMap.put("status", 200);

resultMap.put("message", "登入成功");

//更新使用者最後登入時間

Subject currentUser = SecurityUtils.getSubject();

User luser = (User) currentUser.getPrincipal();

User user1 = new User();

user1.setId(luser.getId());

user1.setLastLogDate(new Date());

userService.updateUserByIdSelective(user1);//更新使用者方法

} catch (Exception e) {

resultMap.put("message", "未知系統錯誤:" + e.getMessage());

}

return resultMap;

}else{//not has key

resultMap.put("status", 0);

return resultMap;

}*/

}

第五servie

1:userService

@Override

public void saveWxUser(String state, JSONObject infoJson) {

logger.info("state:"+state+"==infoJson:"+infoJson);

SysUserInfo userInfo = new SysUserInfo();

userInfo.setCharUserCode(state);

userInfo.setCharUserName(infoJson.toJSONString());

this.save(userInfo);

}

@Override

public String getWxUser(String sessionId) {

List<Map<String,Object>> list = this.findBySql("select charUserName from SysUserInfo where charUserCode=\'"+sessionId+"\'");

if(list!=null&&list.size()>0){

return list.get(0).get("CHARUSERNAME").toString();

}

return null;

}

@Override

public void delWxUser(String sessionId) {

this.executeSql("update SysUserInfo set charUserCode=\'"+sessionId+"已删除\' where charUserCode=\'"+sessionId+"\'");

}

@Override

public SysUserInfo selectUserByWechat(String openId) {

List<SysUserInfo> list = this.find("from SysUserInfo where charUserName=\'"+openId+"\'");

if(list!=null&&list.size()>0){

return list.get(0);

}

return null;

}

2:AuthService 

public interface AuthService {

public abstract String getAccessToken(String code);

public abstract String getOpenId(String accessToken);

public abstract String refreshToken(String code);

public abstract String getAuthorizationUrl(String type,String state) throws UnsupportedEncodingException;

public abstract JSONObject getUserInfo(String accessToken,String openId);

}

3:DefaultAuthServiceImpl 

public abstract class DefaultAuthServiceImpl implements AuthService{

public static RestTemplate getRestTemplate() {// 手動添加

SimpleClientHttpRequestFactory requestFactory=new SimpleClientHttpRequestFactory();

requestFactory.setReadTimeout(120000);

List<HttpMessageConverter<?>> messageConverters = new LinkedList<>();

messageConverters.add(new ByteArrayHttpMessageConverter());

messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));

messageConverters.add(new ResourceHttpMessageConverter());

messageConverters.add(new SourceHttpMessageConverter<Source>());

messageConverters.add(new AllEncompassingFormHttpMessageConverter());

messageConverters.add(new MappingJackson2HttpMessageConverter());

RestTemplate restTemplate=new RestTemplate(messageConverters);

restTemplate.setRequestFactory(requestFactory);

return restTemplate;

}

}

4:WeChatAuthServiceImpl 

@Service("weChatAuthServiceImpl")

public class WeChatAuthServiceImpl extends DefaultAuthServiceImpl implements WeChatAuthService {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

//請求此位址即跳轉到二維碼登入界面

private static final String AUTHORIZATION_URL =

"https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";

// 擷取使用者 openid 和access——toke 的 URL

private static final String ACCESSTOKE_OPENID_URL =

"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

private static final String REFRESH_TOKEN_URL =

"https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";

private static final String USER_INFO_URL =

"https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";

private static final String APP_ID="wx58fa4136c0f";

private static final String APP_SECRET="127b28f355110eef97be9eae";

private static final String SCOPE = "snsapi_userinfo";//"snsapi_userinfo"; snsapi_login snsapi_userinfo snsapi_base

//private String pcCallbackUrl = "https://7dc6440a.ngrok.io//wechat/pcAuth"; //pc回調域名

private String pcCallbackUrl = "http://39.23.234.21/chainStore/userController/pcAuth.do"; //pc回調域名

private String mobileCallbackUrl = "https://7dc6440a.ngrok.io//wechat/mobileAuth"; //mobile回調域名

/**

* 第一步,帶着參數

* appid:公衆号的唯一辨別

* redirect_uri:授權後重定向的回調連結位址

* response_type:傳回類型,填寫code

* scope:應用授權作用域,snsapi_base / snsapi_userinfo

* state:非必傳,重定向後會帶上state參數,開發者可以填寫a-zA-Z0-9的參數值,最多128位元組

* wechat_redirect:無論直接打開還是做頁面302重定向時候,必須帶此參數

* */

@Override

public String getAuthorizationUrl(String type,String state) throws UnsupportedEncodingException {

String callbackUrl = "";

Object urlState = "";

if("pc".equals(type)){//移動端 pc端回調方法不一樣

callbackUrl = URLEncoder.encode(pcCallbackUrl,"utf-8");

urlState = state;

}else if("mobile".equals(type)){

callbackUrl = URLEncoder.encode(mobileCallbackUrl,"utf-8");

urlState = System.currentTimeMillis();

}

String url = String.format(AUTHORIZATION_URL,APP_ID,callbackUrl,SCOPE,urlState);

return url;

}

/**

* 第二步

* 傳appid secret code grant_type=authorization_code

* 獲得 access_token openId等

* */

@Override

public String getAccessToken(String code) {

String url = String.format(ACCESSTOKE_OPENID_URL,APP_ID,APP_SECRET,code);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);

URI uri = builder.build().encode().toUri();

String resp = getRestTemplate().getForObject(uri, String.class);

logger.error("getAccessToken resp = "+resp);

if(resp.contains("openid")){

JSONObject jsonObject = JSONObject.parseObject(resp);

String access_token = jsonObject.getString("access_token");

String openId = jsonObject.getString("openid");;

JSONObject res = new JSONObject();

res.put("access_token",access_token);

res.put("openId",openId);

res.put("refresh_token",jsonObject.getString("refresh_token"));

return res.toJSONString();

}else{

logger.error("擷取使用者資訊錯誤,msg = "+resp);

return null;

}

}

//微信接口中,token和openId是一起傳回,故此方法不需實作

@Override

public String getOpenId(String accessToken) {

return null;

}

@Override

public JSONObject getUserInfo(String accessToken, String openId){

String url = String.format(USER_INFO_URL, accessToken, openId);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);

URI uri = builder.build().encode().toUri();

String resp = getRestTemplate().getForObject(uri, String.class);

logger.error("getUserInfo resp = "+resp);

if(resp.contains("errcode")){

logger.error("擷取使用者資訊錯誤,msg = "+resp);

return null;

}else{

JSONObject data =JSONObject.parseObject(resp);

JSONObject result = new JSONObject();

result.put("id",data.getString("unionid"));

result.put("sex",data.getString("sex"));

result.put("nickName",data.getString("nickname"));

result.put("avatar",data.getString("headimgurl"));

return result;

}

}

//微信的token隻有2小時的有效期,過時需要重新擷取,是以官方提供了

//根據refresh_token 重新整理擷取token的方法,本項目僅僅是擷取使用者

//資訊,并将資訊存入庫,是以兩個小時也已經足夠了

@Override

public String refreshToken(String refresh_token) {

String url = String.format(REFRESH_TOKEN_URL,APP_ID,refresh_token);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);

URI uri = builder.build().encode().toUri();

ResponseEntity<JSONObject> resp = getRestTemplate().getForEntity(uri,JSONObject.class);

JSONObject jsonObject = resp.getBody();

String access_token = jsonObject.getString("access_token");

return access_token;

}

}

 5:WeChatAuthService 

public interface WeChatAuthService {

public String getAuthorizationUrl(String string, String sessionId) throws UnsupportedEncodingException;

public String getAccessToken(String code);

public JSONObject getUserInfo(String accessToken, String openId);

}

 需要三個jar包

微信網頁登入