Bladeren bron

github登录绑定

xuexb 6 jaren geleden
bovenliggende
commit
b2e58972bd
17 gewijzigde bestanden met toevoegingen van 393 en 91 verwijderingen
  1. 62 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/configure/ThirdPartyAuthConfiguration.java
  2. 0 1
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/configure/WechatConfiguration.java
  3. 2 2
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/constants/UrlConstants.java
  4. 2 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/data/UserInfo.java
  5. 2 2
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/mapper/UserThirdPartyDao.java
  6. 2 2
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/model/UserThirdParty.java
  7. 29 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/ThirdPartyAuthService.java
  8. 0 19
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/UserThirdPartyService.java
  9. 81 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/impl/ThirdPartyAuthServiceImpl.java
  10. 0 34
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/impl/UserThirdPartyServiceImpl.java
  11. 60 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/PageController.java
  12. 10 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/TestController.java
  13. 0 30
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/ThirdPartyLoginController.java
  14. 8 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/data/UserVO.java
  15. 7 1
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/logic/ThirdPartyLogic.java
  16. 57 0
      mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/logic/impl/ThirdPartyLogicImpl.java
  17. 71 0
      mooctest-user-server/src/main/resources/templates/third_party_bind.html

+ 62 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/configure/ThirdPartyAuthConfiguration.java

@@ -0,0 +1,62 @@
+package cn.iselab.mooctest.user.configure;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @Description: 作用描述
+ * @Author: xuexb
+ * @CreateDate: 19-1-9$ 下午2:21$
+ */
+@Configuration
+public class ThirdPartyAuthConfiguration {
+
+    @Value("${github.clientId}")
+    String gitHubClientId;
+
+    @Value("${github.clientSecret}")
+    String gitHubClientSecret;
+
+    @Bean
+    public RestTemplate getRestTemplate(){
+        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+        factory.setReadTimeout(5000);
+        factory.setConnectTimeout(5000);
+        RestTemplate restTemplate = new RestTemplate(factory);
+        return restTemplate;
+    }
+
+    @Bean
+    public HttpEntity<String> jsonAcceptHeaders(){
+        HttpHeaders httpHeaders = new HttpHeaders();
+        httpHeaders.set("Accept", MediaType.APPLICATION_JSON.toString());
+        httpHeaders.set(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString());
+        HttpEntity<String> entity = new HttpEntity<>(null, httpHeaders);
+        return entity;
+    }
+
+    public String getGitHubClientId() {
+        return gitHubClientId;
+    }
+
+    public void setGitHubClientId(String gitHubClientId) {
+        this.gitHubClientId = gitHubClientId;
+    }
+
+    public String getGitHubClientSecret() {
+        return gitHubClientSecret;
+    }
+
+    public void setGitHubClientSecret(String gitHubClientSecret) {
+        this.gitHubClientSecret = gitHubClientSecret;
+    }
+}

+ 0 - 1
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/configure/WechatConfiguration.java

@@ -41,7 +41,6 @@ public class WechatConfiguration {
     }
 
     public Token getToken(String code) {
-
         if (appId != null && appSecret != null) {
             token = WechatUtil.getToken(appId, appSecret, code);
         }

+ 2 - 2
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/constants/UrlConstants.java

@@ -18,8 +18,8 @@ public class UrlConstants {
 
     public static final String DFAULT_GOTO="http://www.mooctest.net/user/info";
 
-    public static final String GET_GITHUB_LOGIN_ACCESSTOKEN = "https://github.com/login/oauth/authorize?client_id=";
+    public static final String GET_GITHUB_LOGIN_ACCESSTOKEN = "https://github.com/login/oauth/access_token?code=CODE&client_id=CLIENTID&client_secret=CLIENTSECRET";
 
-    public static final String GET_GITHUB_USER_INFO = "";
+    public static final String GET_GITHUB_USER_INFO = "https://api.github.com/user?access_token=ACCESSTOKEN";
 
 }

+ 2 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/data/UserInfo.java

@@ -19,6 +19,8 @@ public class UserInfo {
 
     private String sex;
 
+    private String thirdPartyId;
+
     private String headimgurl;
 
     private String unionid;

+ 2 - 2
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/mapper/UserThirdPartyDao.java

@@ -16,7 +16,7 @@ public interface UserThirdPartyDao extends CrudRepository<UserThirdParty, Long>,
 
     List<UserThirdParty> findByUserId(Long userId);
 
-    UserThirdParty findByThirdPartyIdentityAndFrom(String thirdPartyIdentity, String from);
+    UserThirdParty findByThirdPartyIdentityAndType(String thirdPartyIdentity, String from);
 
-    UserThirdParty findByUserIdAndFrom(Long userId, String from);
+    UserThirdParty findByUserIdAndType(Long userId, String from);
 }

+ 2 - 2
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/model/UserThirdParty.java

@@ -24,8 +24,8 @@ public class UserThirdParty {
     @Column(name = "third_party_identity")
     private String thirdPartyIdentity;
 
-    @Column(name = "from")
-    private String from;
+    @Column(name = "type")
+    private String type;
 
     @Column(name = "is_delete")
     private int isDelete;

+ 29 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/ThirdPartyAuthService.java

@@ -0,0 +1,29 @@
+package cn.iselab.mooctest.user.service;
+
+
+import cn.iselab.mooctest.user.data.UserInfo;
+import cn.iselab.mooctest.user.model.UserThirdParty;
+import org.json.JSONObject;
+
+import java.util.List;
+
+/**
+ * @Description: 作用描述
+ * @Author: xuexb
+ * @CreateDate: 19-1-8$ 上午1:23$
+ */
+public interface ThirdPartyAuthService {
+
+    String getAccessToken(String url, String code);
+
+    UserInfo getGithubUserInfo(String url, String accessToken);
+
+    UserThirdParty findByThirdIdAndType(String identity, String type);
+
+    UserThirdParty save(UserThirdParty userThirdParty);
+
+    List<UserThirdParty> findByUserId(Long userId);
+
+
+
+}

+ 0 - 19
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/UserThirdPartyService.java

@@ -1,19 +0,0 @@
-package cn.iselab.mooctest.user.service;
-
-import cn.iselab.mooctest.user.model.UserThirdParty;
-
-import java.util.List;
-
-/**
- * @Description: 作用描述
- * @Author: xuexb
- * @CreateDate: 19-1-3$ 下午10:27$
- */
-public interface UserThirdPartyService {
-
-    UserThirdParty findByThirdIdAndFrom(String identity, String from);
-
-    UserThirdParty save(UserThirdParty userThirdParty);
-
-    List<UserThirdParty> findByUserId(Long userId);
-}

+ 81 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/impl/ThirdPartyAuthServiceImpl.java

@@ -0,0 +1,81 @@
+package cn.iselab.mooctest.user.service.impl;
+
+import cn.iselab.mooctest.user.configure.ThirdPartyAuthConfiguration;
+import cn.iselab.mooctest.user.data.UserInfo;
+import cn.iselab.mooctest.user.mapper.UserThirdPartyDao;
+import cn.iselab.mooctest.user.model.UserThirdParty;
+import cn.iselab.mooctest.user.service.ThirdPartyAuthService;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+
+
+/**
+ * @Description: 第三方验证服务
+ * @Author: xuexb
+ * @CreateDate: 19-1-8$ 上午1:23$
+ */
+@Service
+public class ThirdPartyAuthServiceImpl implements ThirdPartyAuthService {
+
+    Logger logger = LoggerFactory.getLogger(ThirdPartyAuthServiceImpl.class);
+
+    @Autowired
+    RestTemplate restTemplate;
+
+    @Autowired
+    HttpEntity<String> entity;
+
+    @Autowired
+    UserThirdPartyDao userThirdPartyDao;
+
+    @Override
+    public String getAccessToken(String url, String code) {
+        String result = "";
+        try{
+            url = url.replace("CODE", code);
+            result = restTemplate.exchange(url, HttpMethod.GET, entity, String.class).getBody();
+        }catch (Exception e){
+            logger.error("获取access_token出错", e);
+        }
+        JSONObject object = new JSONObject(result);
+        String accessToken = object.getString("access_token");
+        logger.info("accessToken: "+ accessToken);
+        return accessToken;
+    }
+
+    @Override
+    public UserInfo getGithubUserInfo(String url, String accessToken) {
+        url = url.replace("ACCESSTOKEN", accessToken);
+        String tmp = restTemplate.exchange(url, HttpMethod.GET, entity, String.class).getBody();
+//        String result = restTemplate.getForObject(url ,String.class);
+        JSONObject result = new JSONObject(tmp);
+        UserInfo userInfo = new UserInfo();
+        userInfo.setNickname(result.getString("login"));
+        userInfo.setHeadimgurl(result.getString("avatar_url"));
+        userInfo.setThirdPartyId(""+result.getLong("id"));
+        return userInfo;
+    }
+
+    @Override
+    public UserThirdParty findByThirdIdAndType(String identity, String type) {
+        return userThirdPartyDao.findByThirdPartyIdentityAndType(identity, type);
+    }
+
+    @Override
+    public UserThirdParty save(UserThirdParty userThirdParty) {
+        return userThirdPartyDao.save(userThirdParty);
+    }
+
+    @Override
+    public List<UserThirdParty> findByUserId(Long userId) {
+        return userThirdPartyDao.findByUserId(userId);
+    }
+}

+ 0 - 34
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/service/impl/UserThirdPartyServiceImpl.java

@@ -1,34 +0,0 @@
-package cn.iselab.mooctest.user.service.impl;
-
-import cn.iselab.mooctest.user.mapper.UserThirdPartyDao;
-import cn.iselab.mooctest.user.model.UserThirdParty;
-import cn.iselab.mooctest.user.service.UserThirdPartyService;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import java.util.List;
-
-/**
- * @Description: 第三方帐号相关业务
- * @Author: xuexb
- * @CreateDate: 19-1-4$ 上午9:23$
- */
-public class UserThirdPartyServiceImpl implements UserThirdPartyService {
-
-    @Autowired
-    UserThirdPartyDao userThirdPartyDao;
-
-    @Override
-    public UserThirdParty findByThirdIdAndFrom(String identity, String from) {
-        return userThirdPartyDao.findByThirdPartyIdentityAndFrom(identity, from);
-    }
-
-    @Override
-    public UserThirdParty save(UserThirdParty userThirdParty) {
-        return userThirdPartyDao.save(userThirdParty);
-    }
-
-    @Override
-    public List<UserThirdParty> findByUserId(Long userId) {
-        return userThirdPartyDao.findByUserId(userId);
-    }
-}

+ 60 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/PageController.java

@@ -5,8 +5,13 @@ import cn.iselab.mooctest.user.constants.ResponseStatus;
 import cn.iselab.mooctest.user.constants.UrlConstants;
 import cn.iselab.mooctest.user.data.Callback;
 import cn.iselab.mooctest.user.data.ResponseResult;
+import cn.iselab.mooctest.user.data.UserInfo;
+import cn.iselab.mooctest.user.model.User;
+import cn.iselab.mooctest.user.model.UserThirdParty;
+import cn.iselab.mooctest.user.service.ThirdPartyAuthService;
 import cn.iselab.mooctest.user.util.EncryptionUtil;
 import cn.iselab.mooctest.user.web.data.UserVO;
+import cn.iselab.mooctest.user.web.logic.ThirdPartyLogic;
 import cn.iselab.mooctest.user.web.logic.UserLogic;
 import com.sun.org.apache.xpath.internal.operations.Mod;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +33,12 @@ public class PageController extends BaseController{
     @Autowired
     UserLogic userLogic;
 
+    @Autowired
+    ThirdPartyLogic thirdPartyLogic;
+
+    @Autowired
+    ThirdPartyAuthService thirdPartyAuthService;
+
     @RequestMapping(value = UrlConstants.PAGE + "login", method = RequestMethod.GET)
     public String login(Callback callback, HttpServletRequest request){
         System.out.println(System.currentTimeMillis());
@@ -105,6 +116,55 @@ public class PageController extends BaseController{
         return "success_page";
     }
 
+    @RequestMapping(value = UrlConstants.PAGE + "login/github", method = RequestMethod.GET)
+    public String loginByGithub(@RequestParam("code")String code, Model model, HttpServletRequest request){
+        ResponseResult<Object> result = new ResponseResult<>();
+        System.out.println("code: " + code);
+        result = thirdPartyLogic.loginByGithub(code, request);
+        if (result.getStatus()==ResponseStatus.NOTFOUND){
+            UserInfo userInfo = (UserInfo) result.getData();
+            model.addAttribute("thirdPartyName", userInfo.getNickname());
+            model.addAttribute("thirdPartyId", userInfo.getThirdPartyId());
+            model.addAttribute("headImg", userInfo.getHeadimgurl());
+            model.addAttribute("from", "github");
+            return "third_party_bind";
+        }
+        request.getSession().setAttribute("userId", ((UserThirdParty)result.getData()).getUserId());
+        String redirectUrl = (String)request.getSession().getAttribute("redirectURL");
+        if (redirectUrl==null || redirectUrl.isEmpty())
+            redirectUrl = UrlConstants.DFAULT_GOTO;
+        return "redirect:"+redirectUrl;
+    }
+
+    @RequestMapping(value = UrlConstants.PAGE + "thirdParty/bind", method = RequestMethod.POST)
+    public String thirdPartyBind(UserVO userVO, Model model, HttpServletRequest request){
+        UserVO user = userVO;
+        System.out.println(userVO.toString());
+        user.setPassword(EncryptionUtil.encryptMD5(user.getPassword()));
+        ResponseResult<UserDTO> result = userLogic.checkPWD(user);
+        if (result.getStatus()!=ResponseStatus.SUCCESS){
+            model.addAttribute("result", result);
+            model.addAttribute("thirdPartyName", userVO.getThirdPartyName());
+            model.addAttribute("thirdPartyId", userVO.getThirdPartyId());
+            model.addAttribute("headImg", userVO.getHeadImgUrl());
+            model.addAttribute("from", userVO.getFrom());
+            return "third_party_bind";
+        }
+        UserDTO userToBind = (UserDTO) result.getData();
+        UserThirdParty userThirdParty = new UserThirdParty();
+        userThirdParty.setThirdPartyIdentity(userVO.getThirdPartyId());
+        userThirdParty.setUserId(userToBind.getId());
+        userThirdParty.setType(userVO.getFrom());
+        userThirdParty.setIsDelete(0);
+        System.out.println(userThirdParty.getUserId()+"--"+userThirdParty.getThirdPartyIdentity()+"---"+userThirdParty.getType());
+        thirdPartyAuthService.save(userThirdParty);
+        request.getSession().setAttribute("userId", userThirdParty.getUserId());
+        String redirectUrl = (String)request.getSession().getAttribute("redirectURL");
+        if (redirectUrl==null || redirectUrl.isEmpty())
+            redirectUrl = UrlConstants.DFAULT_GOTO;
+        return "redirect:"+redirectUrl;
+    }
+
     @RequestMapping(value = UrlConstants.PAGE + "forgetPassword/mobile", method = RequestMethod.GET)
     public String forgetPassword(){
         return "forget_password_mobile";

+ 10 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/TestController.java

@@ -1,6 +1,7 @@
 package cn.iselab.mooctest.user.web.ctrl;
 
 import cn.iselab.mooctest.rpc.user.data.UserDTO;
+import cn.iselab.mooctest.user.configure.ThirdPartyAuthConfiguration;
 import cn.iselab.mooctest.user.constants.ResponseStatus;
 import cn.iselab.mooctest.user.data.Callback;
 import cn.iselab.mooctest.user.data.ResponseResult;
@@ -36,6 +37,9 @@ public class TestController extends BaseController{
     @Autowired
     UserLogic userLogic;
 
+    @Autowired
+    ThirdPartyAuthConfiguration authConfiguration;
+
     @RequestMapping(value = "/test/first", method = RequestMethod.GET)
     public Map<String, Object> firstResp(HttpServletRequest request){
         Map<String, Object> map = new HashMap<>();
@@ -132,4 +136,10 @@ public class TestController extends BaseController{
         return modelAndView;
     }
 
+    @RequestMapping(value = "/test/github/appinfo", method = RequestMethod.GET)
+    public String githubInfo(){
+        return "client_id: " + authConfiguration.getGitHubClientId()
+                + "client_secret: "+authConfiguration.getGitHubClientSecret();
+    }
+
 }

+ 0 - 30
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/ctrl/ThirdPartyLoginController.java

@@ -1,30 +0,0 @@
-package cn.iselab.mooctest.user.web.ctrl;
-
-import cn.iselab.mooctest.user.constants.UrlConstants;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @Description: 作用描述
- * @Author: xuexb
- * @CreateDate: 19-1-3$ 下午4:17$
- */
-@RestController
-public class ThirdPartyLoginController extends BaseController {
-
-    @RequestMapping(value = UrlConstants.API + "github/login}", method = RequestMethod.GET)
-    public String loginByGithub(@RequestParam("code") String code){
-
-        return null;
-    }
-
-    @RequestMapping(value = UrlConstants.API + "third/bind", method = RequestMethod.PUT)
-    public String bind(){
-
-        return null;
-    }
-
-}

+ 8 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/data/UserVO.java

@@ -17,4 +17,12 @@ public class UserVO extends UserDTO {
    private String password2;
 
    private String oldPassword;
+
+   private String thirdPartyId;
+
+   private String thirdPartyName;
+
+   private String headImgUrl;
+
+   private String from;
 }

+ 7 - 1
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/logic/ThirdPartyLogic.java

@@ -1,10 +1,16 @@
 package cn.iselab.mooctest.user.web.logic;
 
+import cn.iselab.mooctest.user.data.ResponseResult;
+import cn.iselab.mooctest.user.data.UserInfo;
+
+import javax.servlet.http.HttpServletRequest;
+
 /**
- * @Description: 作用描述
+ * @Description:
  * @Author: xuexb
  * @CreateDate: 19-1-4$ 下午12:11$
  */
 public interface ThirdPartyLogic {
+    ResponseResult<Object> loginByGithub(String code, HttpServletRequest request);
 
 }

+ 57 - 0
mooctest-user-server/src/main/java/cn/iselab/mooctest/user/web/logic/impl/ThirdPartyLogicImpl.java

@@ -0,0 +1,57 @@
+package cn.iselab.mooctest.user.web.logic.impl;
+
+import cn.iselab.mooctest.user.configure.ThirdPartyAuthConfiguration;
+import cn.iselab.mooctest.user.constants.ResponseStatus;
+import cn.iselab.mooctest.user.constants.UrlConstants;
+import cn.iselab.mooctest.user.data.ResponseResult;
+import cn.iselab.mooctest.user.data.UserInfo;
+import cn.iselab.mooctest.user.model.UserThirdParty;
+import cn.iselab.mooctest.user.service.ThirdPartyAuthService;
+import cn.iselab.mooctest.user.web.logic.BaseLogic;
+import cn.iselab.mooctest.user.web.logic.ThirdPartyLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @Description: 第三方验证等
+ * @Author: xuexb
+ * @CreateDate: 19-1-10$ 上午1:25$
+ */
+@Service
+public class ThirdPartyLogicImpl extends BaseLogic implements ThirdPartyLogic {
+
+    @Autowired
+    ThirdPartyAuthService thirdPartyAuthService;
+
+    @Autowired
+    ThirdPartyAuthConfiguration thirdPartyAuthConfiguration;
+
+    @Override
+    public ResponseResult<Object> loginByGithub(String code, HttpServletRequest request) {
+        ResponseResult<Object> result = new ResponseResult<>();
+        UserInfo userInfo = null;
+        try{
+            userInfo = thirdPartyAuthService.getGithubUserInfo(UrlConstants.GET_GITHUB_USER_INFO
+                    , thirdPartyAuthService.getAccessToken(UrlConstants.GET_GITHUB_LOGIN_ACCESSTOKEN
+                                    .replace("CLIENTID", thirdPartyAuthConfiguration.getGitHubClientId())
+                                    .replace("CLIENTSECRET", thirdPartyAuthConfiguration.getGitHubClientSecret())
+                            , code));
+        }catch (Exception e){
+            result.init(ResponseStatus.FAILED, "获取第三方用户信息出错", null);
+            LOG.error(result.getMsg(), e);
+            return result;
+        }
+        UserThirdParty userThirdParty = thirdPartyAuthService.findByThirdIdAndType(userInfo.getThirdPartyId(), "github");
+        if (userThirdParty == null){
+            result.init(ResponseStatus.NOTFOUND, "未绑定mooctest帐号", userInfo);
+            LOG.info(result.getMsg());
+            return result;
+        }
+        result.init(ResponseStatus.SUCCESS, "登录成功", userThirdParty);
+        request.getSession().setAttribute("userId", userThirdParty.getUserId());
+        LOG.info(result.getMsg());
+        return result;
+    }
+}

+ 71 - 0
mooctest-user-server/src/main/resources/templates/third_party_bind.html

@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html lang="zh-CN" xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:th="http://www.thymeleaf.org">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>慕测平台</title>
+    <meta name="keywords" content="" />
+    <meta name="description" content="" />
+
+    <link rel="stylesheet" type="text/css" th:href="@{/vendor/bootstrap/css/bootstrap.min.css}">
+    <link rel="stylesheet" type="text/css" th:href="@{/fonts/font-awesome-4.7.0/css/font-awesome.min.css}">
+    <link rel="stylesheet" type="text/css" th:href="@{/fonts/iconic/css/material-design-iconic-font.min.css}">
+    <link rel="stylesheet" type="text/css" th:href="@{/css/util.css}">
+    <link rel="stylesheet" type="text/css" th:href="@{/css/main.css}">
+</head>
+
+<body>
+
+<div class="limiter">
+    <div class="container-login100" th:style="'background-image:url(/images/bg.jpg);'">
+        <div class="wrap-login100 p-l-40 p-r-40 p-t-30 p-b-25">
+            <form th:action="@{/page/thirdParty/bind}" method="post" class="login100-form validate-form">
+
+                <div id="login-logo" style="text-align: center;">
+                    <img  style="width: 80px; border-radius: 50%;" th:src="${headImg}" >
+                </div>
+
+                <span class="login100-form-title p-b-30" th:text="${thirdPartyName}">MOOCTEST</span>
+                <input id="thirdPartyName" name="thirdPartyName" type="hidden" th:value="${thirdPartyName}">
+                <input id="thirdPartyId" name="thirdPartyId" type="hidden" th:value="${thirdPartyId}">
+                <input id="from" name="from" type="hidden" th:value="${from}">
+                <input id="headImgUrl" name="headImgUrl" type="hidden" th:value="${headImg}">
+                <div class="wrap-input100 validate-input m-b-23" data-validate="请输入用户名">
+                    <span class="label-input100">邮箱</span>
+                    <input id="email" class="input100" type="text" name="email" placeholder="请输入用户名" required="邮箱账号不可为空">
+                    <span class="focus-input100" data-symbol="&#xf206;"></span>
+                </div>
+
+                <div class="wrap-input100 validate-input" data-validate="请输入密码">
+                    <span class="label-input100">密码</span>
+                    <input id="password" class="input100" type="password" name="password" placeholder="请输入密码" required="密码不可为空">
+                    <span class="focus-input100" data-symbol="&#xf190;"></span>
+                </div>
+
+                <div class="text-center p-t-6 p-b-20">
+                    <span style="color: red" th:text="${result==null}?'&nbsp;':${result.msg}"></span>
+                </div>
+                <div class="container-login100-form-btn">
+                    <div class="wrap-login100-form-btn">
+                        <div class="login100-form-bgbtn"></div>
+                        <button class="login100-form-btn">绑 定</button>
+                    </div>
+                </div>
+
+
+                <div class="flex-col-c p-t-10">
+                    <a href="/page/register" class="txt2">立即注册</a>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>
+
+<script th:src="@{/vendor/jquery/jquery-3.2.1.min.js}"></script>
+<script th:src="@{/js/main.js}"></script>
+</body>
+
+</html>