当前位置:网站首页>13 medical registration system_ [wechat login]
13 medical registration system_ [wechat login]
2022-07-06 10:01:00 【Learn from Tao Ge】
Login requirements
Login requirements
- Login takes the form of pop-up layer
- Login mode :
- Phone number + Mobile phone verification code
- Wechat scanning
- No registration interface , When logging in for the first time, judge whether the system exists according to the mobile phone number , If it does not exist, it will be registered automatically
- If wechat scanning login is successful, you must bind your mobile phone number , namely : Bind the mobile phone number after the first successful scan , After login scanning, direct login succeeds
- The gateway judges the login status uniformly , How to log in , The page pops up the login layer
Wechat login
1、OAuth2
OAuth2 What problem to solve
1.1.1 Open inter system authorization
Photo owners want to print photos on Cloud Print Services , Cloud printing services need to access resources on cloud storage services
1.1.2 legend
Resource owners : Photo owner
Customer applications : Cloud printing
Protected resources : Photo
1.1.3 Mode one : User name password copy
Users will " Cloud storage " User name and password of the service , tell " Cloud printing ", The latter can read the user's photos . There are several serious disadvantages in this way .
(1)" Cloud printing " For follow-up service , Will save the user's password , It's not safe .
(2)Google Had to deploy password login , And we know that , Simple password login is not secure .
(3)" Cloud printing " Have access to user storage in Google Power of all information , Users can't limit " Cloud printing " The scope and validity of the authorization .
(4) The user only has to change the password , To take back the gift " Cloud printing " The power of . But do it , All other third-party applications authorized by users will be invalidated .
(5) As long as a third-party application is cracked , Will cause the user password to leak , And all password protected data leaks .
summary :
Store the user name and password in the protected resource on the server of the client application , Use this user name and password to log in directly
Applicable to multiple systems within the same company , Not for untrusted third party applications
1.1.4 Mode two : General developers key
It is applicable to the cooperation between partners or different business departments of credit granting
1.1.5 Mode three : Issue token
near OAuth2 The way , You need to think about how to manage tokens 、 Issue token 、 Revocation token , Need a unified agreement , So there it is OAuth2 agreement
Tokens are analogous to Valet keys
1.2 OAuth2 The simplest guide
1.2.1 OAuth The main character
1.2.2 The simplest guide
Takako Kawasaki :OAuth2 Domain expert , Developed a OAuth2 sass service ,OAuth2 as Service, And made a company
In the process of financing, in order to explain to investors OAuth2 What is it? , So I wrote an article ,《OAuth2 The simplest guide 》
1.3 OAuth2 Application
1.3.1 Microservice security
OAuth2 Solve single sign on problem
In modern microservices, there are more and more forms of microservices and applications and types of devices , You can't log in the traditional way
The core technology is not user name and password , It is token, from AuthServer Issued by token, The user to use token Log in
1.3.2 Social login
2、 Wechat login introduction
2.1 Preparation
1、 register
Wechat open platform :https://open.weixin.qq.com
2、 Mailbox activation
3、 Improve developer profile
4、 Developer qualification
Prepare the business license ,1-2 Approval within working days 、300 element
5、 Create web apps
Submit audit ,7 Approval within working days
6、 Intranet through
ngrok Use
2.2 Authorization process
Reference documents :https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=e547653f995d8f402704d5cb2945177dc8aa4e7e&lang=zh_CN
obtain access_token Sequence diagram
First step : request CODE( Generate Authorization URL)
The second step : adopt code obtain access_token( Development callback URL)
3、 Server side development
Operation module :service-user
explain : Wechat login QR code is opened in the form of pop-up layer , Not in the form of pages , So the practice is different , Refer to the link below , There are ways to pop up layers
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
Pictured :
Therefore, our operation steps are :
The first step is to return the corresponding parameters to the page through the interface ;
The second step is to start the wechat login QR code on the header page ;
Step 3: handle the login callback interface ;
Step 4 callback the return page to notify the wechat login layer that the callback is successful
Step 5: if it is the first scan login , Then bind the mobile number , Login successful
Next we follow the steps , Step by step
3.1 Return wechat login parameters
3.1.1 Add the configuration
stay application-dev.yml Add the configuration
wx.open.app_id=wxed9954c01bb89b47
wx.open.app_secret=a7482517235173ddb4083788de60b90e
wx.open.redirect_url=http://guli.shop/api/ucenter/wx/callback
yygh.baseUrl=http://localhost:3000
3.1.2 Add configuration class
@Component
public class ConstantPropertiesUtil implements InitializingBean {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
@Value("${yygh.baseUrl}")
private String yyghBaseUrl;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
public static String YYGH_BASE_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appId;
WX_OPEN_APP_SECRET = appSecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
YYGH_BASE_URL = yyghBaseUrl;
}
}
3.1.3 Add interface
add to com.atguigu.yygh.user.api.WeixinApiController class
@Controller
@RequestMapping("/api/ucenter/wx")
public class WeixinApiController {
@Autowired
private UserInfoService userInfoService;
@Autowired
private RedisTemplate redisTemplate;
/** * Get wechat login parameters */
@GetMapping("getLoginParam")
@ResponseBody
public Result genQrConnect(HttpSession session) throws UnsupportedEncodingException {
String redirectUri = URLEncoder.encode(ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL, "UTF-8");
Map<String, Object> map = new HashMap<>();
map.put("appid", ConstantPropertiesUtil.WX_OPEN_APP_ID);
map.put("redirectUri", redirectUri);
map.put("scope", "snsapi_login");
map.put("state", System.currentTimeMillis()+"");//System.currentTimeMillis()+""
return Result.ok(map);
}
}
3.2 The front end displays the login QR code
3.2.1 encapsulation api request
establish /api/user/wexin.js file
import request from '@/utils/request'
const api_name = `/api/ucenter/wx`
export default {
getLoginParam() {
return request({
url: `${
api_name}/getLoginParam`,
method: `get`
})
}
}
3.2.2 Modify components
modify layouts/myheader.vue file , Add wechat QR code login logic
1、 introduce api
import weixinApi from '@/api/weixin'
2、 Introducing WeChat js
mounted() {
// Register the global login event object
window.loginEvent = new Vue();
// Listen for login events
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// Triggering event , Show login layer :loginEvent.$emit('loginDialogEvent')
// Initialize wechat js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
// Wechat login callback processing
let self = this;
window["loginCallback"] = (name,token, openid) => {
self.loginCallback(name, token, openid);
}
},
3、 Instantiate wechat JS object
Add wechat login method
loginCallback(name, token, openid) {
// Open the mobile login layer , Bind cell phone number , The change logic is consistent with the mobile login
if(openid != null) {
this.userInfo.openid = openid
this.showLogin()
} else {
this.setCookies(name, token)
}
},
weixinLogin() {
this.dialogAtrr.showLoginType = 'weixin'
weixinApi.getLoginParam().then(response => {
var obj = new WxLogin({
self_redirect:true,
id: 'weixinLogin', // Containers that need to be displayed id
appid: response.data.appid, // official account appid wx*******
scope: response.data.scope, // The default page is OK
redirect_uri: response.data.redirect_uri, // Callback after successful authorization url
state: response.data.state, // Can be set as simple random number plus session Used to verify
style: 'black', // Provide "black"、"white" Optional . The style of the QR code
href: '' // external css file url, need https
})
})
},
explain : Wechat login method has been bound weixinLogin(), view pages
- test
Refresh the page , See the effect
3.3 Handle wechat callback
3.3.1 add to httpclient Tool class
add to com.atguigu.yygh.user.util.HttpClientUtils class
public class HttpClientUtils {
public static final int connTimeout=10000;
public static final int readTimeout=10000;
public static final String charset="UTF-8";
private static HttpClient client = null;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(128);
cm.setDefaultMaxPerRoute(128);
client = HttpClients.custom().setConnectionManager(cm).build();
}
public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String get(String url) throws Exception {
return get(url, charset, null, null);
}
public static String get(String url, String charset) throws Exception {
return get(url, charset, connTimeout, readTimeout);
}
/** * Send a Post request , Use the specified character set encoding . * * @param url * @param body RequestBody * @param mimeType for example application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3 * @param charset code * @param connTimeout Establish link timeout , millisecond . * @param readTimeout Response timeout , millisecond . * @return ResponseBody, Use the specified character set encoding . * @throws ConnectTimeoutException Link establishment timeout exception * @throws SocketTimeoutException Response timeout * @throws Exception */
public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
String result = "";
try {
if (StringUtils.isNotBlank(body)) {
HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
post.setEntity(entity);
}
// Set parameters
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res;
if (url.startsWith("https")) {
// perform Https request .
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// perform Http request .
client = HttpClientUtils.client;
res = client.execute(post);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/** * Submit form Forms * * @param url * @param params * @param connTimeout * @param readTimeout * @return * @throws ConnectTimeoutException * @throws SocketTimeoutException * @throws Exception */
public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
Set<Entry<String, String>> entrySet = params.entrySet();
for (Entry<String, String> entry : entrySet) {
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
post.setEntity(entity);
}
if (headers != null && !headers.isEmpty()) {
for (Entry<String, String> entry : headers.entrySet()) {
post.addHeader(entry.getKey(), entry.getValue());
}
}
// Set parameters
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// perform Https request .
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// perform Http request .
client = HttpClientUtils.client;
res = client.execute(post);
}
return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null
&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
}
/** * Send a GET request */
public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)
throws ConnectTimeoutException,SocketTimeoutException, Exception {
HttpClient client = null;
HttpGet get = new HttpGet(url);
String result = "";
try {
// Set parameters
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
get.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// perform Https request .
client = createSSLInsecureClient();
res = client.execute(get);
} else {
// perform Http request .
client = HttpClientUtils.client;
res = client.execute(get);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
get.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/** * from response get charset */
@SuppressWarnings("unused")
private static String getCharsetFromResponse(HttpResponse ressponse) {
// Content-Type:text/html; charset=GBK
if (ressponse.getEntity() != null && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {
String contentType = ressponse.getEntity().getContentType().getValue();
if (contentType.contains("charset=")) {
return contentType.substring(contentType.indexOf("charset=") + 8);
}
}
return null;
}
/** * establish SSL Connect * @return * @throws GeneralSecurityException */
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
});
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (GeneralSecurityException e) {
throw e;
}
}
}
3.3.2 Add a callback interface to get access_token
stay WeixinApiController Class to add callback methods
/** * Wechat login callback * * @param code * @param state * @return */
@RequestMapping("callback")
public String callback(String code, String state) {
// Obtain authorized temporary tickets
System.out.println(" Wechat authorization server callback ......");
System.out.println("state = " + state);
System.out.println("code = " + code);
if (StringUtils.isEmpty(state) || StringUtils.isEmpty(code)) {
log.error(" Illegal callback request ");
throw new YyghException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
}
// Use code and appid as well as appscrect Exchange for access_token
StringBuffer baseAccessTokenUrl = new StringBuffer()
.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=%s")
.append("&secret=%s")
.append("&code=%s")
.append("&grant_type=authorization_code");
String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
ConstantPropertiesUtil.WX_OPEN_APP_ID,
ConstantPropertiesUtil.WX_OPEN_APP_SECRET,
code);
String result = null;
try {
result = HttpClientUtils.get(accessTokenUrl);
} catch (Exception e) {
throw new YyghException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
}
System.out.println(" Use code In exchange access_token result = " + result);
JSONObject resultJson = JSONObject.parseObject(result);
if(resultJson.getString("errcode") != null){
log.error(" obtain access_token Failure :" + resultJson.getString("errcode") + resultJson.getString("errmsg"));
throw new YyghException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
}
String accessToken = resultJson.getString("access_token");
String openId = resultJson.getString("openid");
log.info(accessToken);
log.info(openId);
// according to access_token Get the basic information of wechat users
// First, according to openid Do database query
// UserInfo userInfo = userInfoService.getByOpenid(openId);
// If no user information is found , Then call the wechat personal information acquisition interface
// if(null == userInfo){
// If you find personal information , Then log in directly
// Use access_token In exchange for protected resources : Wechat personal information
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openId);
String resultUserInfo = null;
try {
resultUserInfo = HttpClientUtils.get(userInfoUrl);
} catch (Exception e) {
throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
}
System.out.println(" Use access_token Get the result of user information = " + resultUserInfo);
JSONObject resultUserInfoJson = JSONObject.parseObject(resultUserInfo);
if(resultUserInfoJson.getString("errcode") != null){
log.error(" Failed to get user information :" + resultUserInfoJson.getString("errcode") + resultUserInfoJson.getString("errmsg"));
throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
}
// Parsing user information
String nickname = resultUserInfoJson.getString("nickname");
String headimgurl = resultUserInfoJson.getString("headimgurl");
UserInfo userInfo = new UserInfo();
userInfo.setOpenid(openId);
userInfo.setNickName(nickname);
userInfo.setStatus(1);
userInfoService.save(userInfo);
// }
Map<String, Object> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
if(StringUtils.isEmpty(userInfo.getPhone())) {
map.put("openid", userInfo.getOpenid());
} else {
map.put("openid", "");
}
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
return "redirect:" + ConstantPropertiesUtil.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token")+"&openid="+map.get("openid")+"&name="+URLEncoder.encode((String)map.get("name"));
}
3.3.3 Get user information
3.3.3.1 according to openid Query whether the user is registered
1、UserInfoService Class add interface
/** * According to wechat openid Get user information * @param openid * @return */
UserInfo getByOpenid(String openid);
2、UserInfoServiceImpl Class to add an interface implementation
@Override
public UserInfo getByOpenid(String openid) {
return userInfoMapper.selectOne(new QueryWrapper<UserInfo>().eq("openid", openid));
}
3.3.3.2 according to access_token Get user information
@Autowired
private UserInfoService userInfoService;
@RequestMapping("callback")
public String callback(String code, String state) {
// Obtain authorized temporary tickets
...
// according to access_token Get the basic information of wechat users
// First, according to openid Do database query
UserInfo userInfo = userInfoService.getByOpenid(openId);
// If no user information is found , Then call the wechat personal information acquisition interface
if(null == userInfo){
// If you find personal information , Then log in directly
// Use access_token In exchange for protected resources : Wechat personal information
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo"+
"?access_token=%s"+
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openId);
String resultUserInfo = null;
try {
resultUserInfo = HttpClientUtils.get(userInfoUrl);
} catch (Exception e) {
throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
}
System.out.println(" Use access_token Get the result of user information = "+ resultUserInfo);
JSONObject resultUserInfoJson = JSONObject.parseObject(resultUserInfo);
if(resultUserInfoJson.getString("errcode") != null){
log.error(" Failed to get user information :"+ resultUserInfoJson.getString("errcode") + resultUserInfoJson.getString("errmsg"));
throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
}
// Parsing user information
String nickname = resultUserInfoJson.getString("nickname");
String headimgurl = resultUserInfoJson.getString("headimgurl");
userInfo = new UserInfo();
userInfo.setOpenid(openId);
userInfo.setNickName(nickname);
userInfo.setStatus(1);
userInfoService.save(userInfo);
}
Map<String, Object> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
if(StringUtils.isEmpty(userInfo.getPhone())) {
map.put("openid", userInfo.getOpenid());
} else {
map.put("openid", "");
}
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
return "redirect:"+ ConstantPropertiesUtil.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token")+"&openid="+map.get("openid")+"&name="+URLEncoder.encode((String)map.get("name"));
}
explain : We return according to openid Determine whether to bind the mobile number , If you need to bind , Then we have to according to openid User user information , Then update your mobile number
3.4 The callback returns to the page
operation :yygh-site
explain : We only expect to return an empty page , Then communicate with the login layer , In fact, it is a transition page , So we need to define an empty template for this transition page
3.4.1 Define an empty module
Add an empty template component :/layouts/empty.vue
<template>
<div>
<nuxt/>
</div>
</template>
3.4.2 The callback returns to the page
According to the return path /weixin/cakkback, We create components /weixin/cakkback.vue
<template>
<!-- header -->
<div>
</div>
<!-- footer -->
</template>
<script>
export default {
layout: "empty",
data() {
return {
}
},
mounted() {
let token = this.$route.query.token
let name = this.$route.query.name
let openid = this.$route.query.openid
// Call parent vue Method
window.parent['loginCallback'](name, token, openid)
}
}
</script>
explain : On the page, we can receive the returned parameters
3.4.3 The parent component defines the callback method
stay myheader.vue Add method
mounted() {
// Register the global login event object
window.loginEvent = new Vue();
// Listen for login events
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// Triggering event , Show login layer :loginEvent.$emit('loginDialogEvent')
// Initialize wechat js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
// Wechat login callback processing
let self = this;
window["loginCallback"] = (name,token, openid) => {
self.loginCallback(name, token, openid);
}
},
loginCallback(name, token, openid) {
// Open the mobile login layer , Bind cell phone number , The change logic is consistent with the mobile login
if(openid != '') {
this.userInfo.openid = openid
this.showLogin()
} else {
this.setCookies(name, token)
}
},
3.5 The server binds the mobile number
Page binding mobile number will put openid Pass it on , We according to the openid Find user information , Then bind the mobile number
modify UserInfoServiceImpl Class login method
@Override
public Map<String, Object> login(LoginVo loginVo) {
String phone = loginVo.getPhone();
String code = loginVo.getCode();
// Calibration parameters
if(StringUtils.isEmpty(phone) ||
StringUtils.isEmpty(code)) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
// Verification code
String mobleCode = redisTemplate.opsForValue().get(phone);
if(!code.equals(mobleCode)) {
throw new YyghException(ResultCodeEnum.CODE_ERROR);
}
// Bind mobile number
UserInfo userInfo = null;
if(!StringUtils.isEmpty(loginVo.getOpenid())) {
userInfo = this.getByOpenid(loginVo.getOpenid());
if(null != userInfo) {
userInfo.setPhone(loginVo.getPhone());
this.updateById(userInfo);
} else {
throw new YyghException(ResultCodeEnum.DATA_ERROR);
}
}
//userInfo=null Explain that the mobile phone can log in directly
if(null == userInfo) {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("phone", phone);
userInfo = userInfoMapper.selectOne(queryWrapper);
if(null == userInfo) {
userInfo = new UserInfo();
userInfo.setName("");
userInfo.setPhone(phone);
userInfo.setStatus(1);
this.save(userInfo);
}
}
// Check if it is disabled
if(userInfo.getStatus() == 0) {
throw new YyghException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
}
// Log in
UserLoginRecord userLoginRecord = new UserLoginRecord();
userLoginRecord.setUserId(userInfo.getId());
userLoginRecord.setIp(loginVo.getIp());
userLoginRecordMapper.insert(userLoginRecord);
// Return to the page display name
Map<String, Object> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
return map;
}
3.6 myheader.vue Complete code
<template>
<div class="header-container">
<div class="wrapper">
<!-- logo -->
<div class="left-wrapper v-link selected">
<img style="width: 50px" width="50" height="50" src="~assets/images/logo.png">
<span class="text"> Shang Yitong Unified reservation and registration platform </span>
</div>
<!-- Search box -->
<div class="search-wrapper">
<div class="hospital-search animation-show">
<el-autocomplete
class="search-input small"
prefix-icon="el-icon-search"
v-model="state"
:fetch-suggestions="querySearchAsync"
placeholder=" Click to enter the name of the hospital "
@select="handleSelect"
>
<span slot="suffix" class="search-btn v-link highlight clickable selected"> Search for </span>
</el-autocomplete>
</div>
</div>
<!-- On the right side -->
<!-- On the right side -->
<div class="right-wrapper">
<span class="v-link clickable"> Help center </span>
<span v-if="name == ''" class="v-link clickable" @click="showLogin()" id="loginDialog"> Sign in / register </span>
<el-dropdown v-if="name != ''" @command="loginMenu">
<span class="el-dropdown-link">
{
{ name }}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu class="user-name-wrapper" slot="dropdown">
<el-dropdown-item command="/user"> Real name authentication </el-dropdown-item>
<el-dropdown-item command="/order"> Registered order </el-dropdown-item>
<el-dropdown-item command="/patient"> Patient management </el-dropdown-item>
<el-dropdown-item command="/logout" divided> Log out </el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<!-- Login pop-up layer -->
<el-dialog :visible.sync="dialogUserFormVisible" style="text-align: left;" top="50px" :append-to-body="true" width="960px" @close="closeDialog()">
<div class="container">
<!-- Mobile phone login #start -->
<div class="operate-view" v-if="dialogAtrr.showLoginType === 'phone'">
<div class="wrapper" style="width: 100%">
<div class="mobile-wrapper" style="position: static;width: 70%">
<span class="title">{
{ dialogAtrr.labelTips }}</span>
<el-form>
<el-form-item>
<el-input v-model="dialogAtrr.inputValue" :placeholder="dialogAtrr.placeholder" :maxlength="dialogAtrr.maxlength" class="input v-input">
<span slot="suffix" class="sendText v-link" v-if="dialogAtrr.second > 0">{
{ dialogAtrr.second }}s </span>
<span slot="suffix" class="sendText v-link highlight clickable selected" v-if="dialogAtrr.second == 0" @click="getCodeFun()"> To resend </span>
</el-input>
</el-form-item>
</el-form>
<div class="send-button v-button" @click="btnClick()"> {
{ dialogAtrr.loginBtn }}</div>
</div>
<div class="bottom">
<div class="wechat-wrapper" @click="weixinLogin()"><span
class="iconfont icon"></span></div>
<span class="third-text"> Third party account login </span></div>
</div>
</div>
<!-- Mobile phone login #end -->
<!-- Wechat login #start -->
<div class="operate-view" v-if="dialogAtrr.showLoginType === 'weixin'" >
<div class="wrapper wechat" style="height: 400px">
<div>
<div id="weixinLogin"></div>
</div>
<div class="bottom wechat" style="margin-top: -80px;">
<div class="phone-container">
<div class="phone-wrapper" @click="phoneLogin()"><span
class="iconfont icon"></span></div>
<span class="third-text"> SMS verification code login </span></div>
</div>
</div>
</div>
<!-- Wechat login #end -->
<div class="info-wrapper">
<div class="code-wrapper">
<div><img src="//img.114yygh.com/static/web/code_login_wechat.png" class="code-img">
<div class="code-text"><span class="iconfont icon"></span> Wechat scanning and attention
</div>
<div class="code-text"> “ Quick appointment registration ”</div>
</div>
<div class="wechat-code-wrapper"><img
src="//img.114yygh.com/static/web/code_app.png"
class="code-img">
<div class="code-text"> Scan and download </div>
<div class="code-text"> “ Make an appointment for registration ”APP</div>
</div>
</div>
<div class="slogan">
<div>xxxxxx Officially designated platform </div>
<div> Fast registration Be safe </div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import cookie from 'js-cookie'
import Vue from 'vue'
import userInfoApi from '@/api/userInfo'
import smsApi from '@/api/msm'
import hospitalApi from '@/api/hosp'
import weixinApi from '@/api/weixin'
const defaultDialogAtrr = {
showLoginType: 'phone', // Control the switching between mobile login and wechat login
labelTips: ' Phone number ', // Input box prompt
inputValue: '', // Input box binding object
placeholder: ' Please input your mobile number ', // Input box placeholder
maxlength: 11, // Input box length control
loginBtn: ' Get verification code ', // Login button or get verification code button text
sending: true, // Whether the verification code can be sent
second: -1, // Countdown time second>0 : Show countdown second=0 : To resend second=-1 : Show nothing
clearSmsTime: null // Countdown timer task reference Close the login layer and clear the scheduled task
}
export default {
data() {
return {
userInfo: {
phone: '',
code: '',
openid: ''
},
dialogUserFormVisible: false,
// Pop up layer related properties
dialogAtrr:defaultDialogAtrr,
name: '' // The name displayed when the user logs in
}
},
created() {
this.showInfo()
},
mounted() {
// Register the global login event object
window.loginEvent = new Vue();
// Listen for login events
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// Triggering event , Show login layer :loginEvent.$emit('loginDialogEvent')
// Initialize wechat js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
// Wechat login callback processing
let self = this;
window["loginCallback"] = (name,token, openid) => {
self.loginCallback(name, token, openid);
}
},
methods: {
loginCallback(name, token, openid) {
// Open the mobile login layer , Bind cell phone number , The change logic is consistent with the mobile login
if(openid != '') {
this.userInfo.openid = openid
this.showLogin()
} else {
this.setCookies(name, token)
}
},
// Bind login or get verification code button
btnClick() {
// Determine whether to obtain the verification code or log in
if(this.dialogAtrr.loginBtn == ' Get verification code ') {
this.userInfo.phone = this.dialogAtrr.inputValue
// Get verification code
this.getCodeFun()
} else {
// Sign in
this.login()
}
},
// Bind login , Click to display the login layer
showLogin() {
this.dialogUserFormVisible = true
// Initialize login layer related parameters
this.dialogAtrr = { ...defaultDialogAtrr }
},
// Sign in
login() {
this.userInfo.code = this.dialogAtrr.inputValue
if(this.dialogAtrr.loginBtn == ' Submitting ...') {
this.$message.error(' Repeated submission ')
return;
}
if (this.userInfo.code == '') {
this.$message.error(' Verification code must be entered ')
return;
}
if (this.userInfo.code.length != 6) {
this.$message.error(' The format of the verification code is incorrect ')
return;
}
this.dialogAtrr.loginBtn = ' Submitting ...'
userInfoApi.login(this.userInfo).then(response => {
console.log(response.data)
// Login successful Set up cookie
this.setCookies(response.data.name, response.data.token)
}).catch(e => {
this.dialogAtrr.loginBtn = ' Log in right now '
})
},
setCookies(name, token) {
cookie.set('token', token, { domain: 'localhost' })
cookie.set('name', name, { domain: 'localhost' })
window.location.reload()
},
// Get verification code
getCodeFun() {
if (!(/^1[34578]\d{9}$/.test(this.userInfo.phone))) {
this.$message.error(' The mobile number is incorrect ')
return;
}
// Initialization of captcha related properties
this.dialogAtrr.inputValue = ''
this.dialogAtrr.placeholder = ' Please enter the verification code '
this.dialogAtrr.maxlength = 6
this.dialogAtrr.loginBtn = ' Log in right now '
// Control repeat transmissions
if (!this.dialogAtrr.sending) return;
// Send SMS verification code
this.timeDown();
this.dialogAtrr.sending = false;
smsApi.sendCode(this.userInfo.phone).then(response => {
this.timeDown();
}).catch(e => {
this.$message.error(' fail in send , To resend ')
// fail in send , Back to the reacquire captcha interface
this.showLogin()
})
},
// count down
timeDown() {
if(this.clearSmsTime) {
clearInterval(this.clearSmsTime);
}
this.dialogAtrr.second = 60;
this.dialogAtrr.labelTips = ' The captcha has been sent to ' + this.userInfo.phone
this.clearSmsTime = setInterval(() => {
--this.dialogAtrr.second;
if (this.dialogAtrr.second < 1) {
clearInterval(this.clearSmsTime);
this.dialogAtrr.sending = true;
this.dialogAtrr.second = 0;
}
}, 1000);
},
// Close the login layer
closeDialog() {
if(this.clearSmsTime) {
clearInterval(this.clearSmsTime);
}
},
showInfo() {
let token = cookie.get('token')
if (token) {
this.name = cookie.get('name')
console.log(this.name)
}
},
loginMenu(command) {
if('/logout' == command) {
cookie.set('name', '', {domain: 'localhost'})
cookie.set('token', '', {domain: 'localhost'})
// Jump to the page
window.location.href = '/'
} else {
window.location.href = command
}
},
handleSelect(item) {
window.location.href = '/hospital/' + item.hoscode
},
weixinLogin() {
this.dialogAtrr.showLoginType = 'weixin'
weixinApi.getLoginParam().then(response => {
var obj = new WxLogin({
self_redirect:true,
id: 'weixinLogin', // Containers that need to be displayed id
appid: response.data.appid, // official account appid wx*******
scope: response.data.scope, // The default page is OK
redirect_uri: response.data.redirectUri, // Callback after successful authorization url
state: response.data.state, // Can be set as simple random number plus session Used to verify
style: 'black', // Provide "black"、"white" Optional . The style of the QR code
href: '' // external css file url, need https
})
})
},
phoneLogin() {
this.dialogAtrr.showLoginType = 'phone'
this.showLogin()
}
}
}
</script>
边栏推荐
猜你喜欢
Docker MySQL solves time zone problems
Defensive C language programming in embedded development
在CANoe中通過Panel面板控制Test Module 運行(初級)
机械工程师和电气工程师方向哪个前景比较好?
面试突击62:group by 有哪些注意事项?
C杂讲 浅拷贝 与 深拷贝
[NLP] bert4vec: a sentence vector generation tool based on pre training
PR 2021 quick start tutorial, first understanding the Premiere Pro working interface
The 32 year old programmer left and was admitted by pinduoduo and foreign enterprises. After drying out his annual salary, he sighed: it's hard to choose
再有人问你数据库缓存一致性的问题,直接把这篇文章发给他
随机推荐
docker MySQL解决时区问题
PR 2021 quick start tutorial, first understanding the Premiere Pro working interface
宝塔的安装和flask项目部署
vscode 常用的指令
在CANoe中通過Panel面板控制Test Module 運行(初級)
零基础学习单片机切记这四点要求,少走弯路
Redis集群方案应该怎么做?都有哪些方案?
C杂讲 浅拷贝 与 深拷贝
June brush question 02 - string
C#/. Net phase VI 01C Foundation_ 01: running environment, process of creating new C program, strict case sensitivity, meaning of class library
寶塔的安裝和flask項目部署
Can I learn PLC at the age of 33
Yarn organizational structure
C杂讲 文件 初讲
Elk project monitoring platform deployment + deployment of detailed use (II)
西南大学:胡航-关于学习行为和学习效果分析
jar运行报错no main manifest attribute
Keep these four requirements in mind when learning single chip microcomputer with zero foundation and avoid detours
C杂讲 文件 续讲
Embedded development is much more difficult than MCU? Talk about SCM and embedded development and design experience