一、自定义WxRealm,继承自AuthorizingRealm

package com.ruoyi.framework.shiro.realm;import com.ruoyi.customer.domain.CustomerInfo;
import com.ruoyi.customer.domain.CustomerLoginLog;
import com.ruoyi.customer.service.ICustomerInfoService;
import com.ruoyi.customer.service.ICustomerLoginLogService;
import com.ruoyi.customer.service.ICustomerLoginService;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;import java.util.HashSet;
import java.util.Set;/*** 微信权限控制*/
public class WxRealm extends AuthorizingRealm {@Autowiredprivate ISysMenuService menuService;@Autowiredprivate ISysRoleService roleService;@Autowiredprivate SysLoginService loginService;@Autowiredprivate ICustomerLoginService customerLoginService;@Autowiredprivate ICustomerInfoService customerInfoService;@Autowiredprivate ICustomerLoginLogService customerLoginLogService;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {SysUser user = ShiroUtils.getSysUser();// 角色列表Set<String> roles = new HashSet<String>();// 功能列表Set<String> menus = new HashSet<String>();SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 管理员拥有所有权限if (user.isAdmin()){info.addRole("admin");info.addStringPermission("*:*:*");}else{roles = roleService.selectRoleKeys(user.getUserId());menus = menuService.selectPermsByUserId(user.getUserId());// 角色加入AuthorizationInfo认证对象info.setRoles(roles);// 权限加入AuthorizationInfo认证对象info.setStringPermissions(menus);}return info;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//微信平台登录UsernamePasswordToken upToken = (UsernamePasswordToken) token;String username = upToken.getUsername();String password = "";if (upToken.getPassword() != null){password = new String(upToken.getPassword());}SimpleAuthenticationInfo info=null;Long customer_id=customerLoginService.selectCustomerByOpenid(upToken.getUsername());if(customer_id == null){//新客户,返回重新注册新增客户信息System.out.println("======================新的用户======================");throw new UnknownAccountException();}else{//已存在用户//添加用户登录日志CustomerLoginLog customerLoginLog=new CustomerLoginLog();customerLoginLog.setCustomerId(customer_id);customerLoginLogService.insertCustomerLoginLog(customerLoginLog);CustomerInfo customerInfo=customerInfoService.selectCustomerInfoByCustomerid(customer_id);info = new SimpleAuthenticationInfo(customerInfo, ((UsernamePasswordToken) token).getPassword(), customerInfo.getNickName());}return info;}/*** 清理缓存权限*/public void clearCachedAuthorizationInfo(){this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());}
}

二、添加WxSessionManager,解决微信没有浏览器session,人工将session放入request请求head中之后,后台session获取的问题,经过该类处理,shiro会自动将抓取的session与服务端比较

package com.ruoyi.framework.shiro.web.session;import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.shiro.session.OnlineSession;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;/*** 自定义session管理器,重写getSessionId方法* 继承DefaultWebSessionManager,重写getSessionId方法,逻辑是如果请求头中有token,就分析token,没有就调用父类的方法,依然按原先分析cookie中的参数* author zxy*/
public class WxSessionManager extends DefaultWebSessionManager {/*** 这个是客户端请求给服务端带的header*/public final static String HEADER_TOKEN_NAME = "X-Nideshop-Token";public final static Logger LOG = LoggerFactory.getLogger(WxSessionManager.class);private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";/*** 重写getSessionId,分析请求头中的指定参数,做用户凭证sessionId*/@Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response){String id = WebUtils.toHttp(request).getHeader(HEADER_TOKEN_NAME);//System.out.println("id:"+id);if(StringUtils.isEmpty(id)){//如果没有携带id参数则按照父类的方式在cookie进行获取//  System.out.println("super:"+super.getSessionId(request, response));return super.getSessionId(request, response);}else{//如果请求头中有 authToken 则其值为sessionIdrequest.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);return id;}}}

三、ShiroConfig注入WxRealm和WxSessionManager

package com.ruoyi.framework.config;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;import com.ruoyi.framework.shiro.realm.WxRealm;
import com.ruoyi.framework.shiro.web.session.WxSessionManager;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.shiro.realm.UserRealm;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
import com.ruoyi.framework.shiro.web.filter.LogoutFilter;
import com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter;
import com.ruoyi.framework.shiro.web.filter.kickout.KickoutSessionFilter;
import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;
import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;/*** 权限配置加载* * @author ruoyi*/
@Configuration
public class ShiroConfig
{//自定义一个cookie名称private static String cookieId = "WX_TOKEN";public static final String PREMISSION_STRING = "perms[\"{0}\"]";// Session超时时间,单位为毫秒(默认30分钟)@Value("${shiro.session.expireTime}")private int expireTime;// 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟@Value("${shiro.session.validationInterval}")private int validationInterval;// 同一个用户最大会话数@Value("${shiro.session.maxSession}")private int maxSession;// 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户@Value("${shiro.session.kickoutAfter}")private boolean kickoutAfter;// 验证码开关@Value("${shiro.user.captchaEnabled}")private boolean captchaEnabled;// 验证码类型@Value("${shiro.user.captchaType}")private String captchaType;// 设置Cookie的域名@Value("${shiro.cookie.domain}")private String domain;// 设置cookie的有效访问路径@Value("${shiro.cookie.path}")private String path;// 设置HttpOnly属性@Value("${shiro.cookie.httpOnly}")private boolean httpOnly;// 设置Cookie的过期时间,秒为单位@Value("${shiro.cookie.maxAge}")private int maxAge;// 登录地址@Value("${shiro.user.loginUrl}")private String loginUrl;// 权限认证失败地址@Value("${shiro.user.unauthorizedUrl}")private String unauthorizedUrl;/*** 缓存管理器 使用Ehcache实现*/@Beanpublic EhCacheManager getEhCacheManager(){net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");EhCacheManager em = new EhCacheManager();if (StringUtils.isNull(cacheManager)){em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));return em;}else{em.setCacheManager(cacheManager);return em;}}/*** 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署*/protected InputStream getCacheManagerConfigFileInputStream(){String configFile = "classpath:ehcache/ehcache-shiro.xml";InputStream inputStream = null;try{inputStream = ResourceUtils.getInputStreamForPath(configFile);byte[] b = IOUtils.toByteArray(inputStream);InputStream in = new ByteArrayInputStream(b);return in;}catch (IOException e){throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);}finally{IOUtils.closeQuietly(inputStream);}}/*** 自定义Realm*/@Beanpublic UserRealm userRealm(EhCacheManager cacheManager){UserRealm userRealm = new UserRealm();userRealm.setCacheManager(cacheManager);return userRealm;}/*** 注入自定义的 Realm* @return MyRealm*/@Beanpublic WxRealm wxRealm() {WxRealm wx_Realm = new WxRealm();return wx_Realm;}/*** 会话管理器*/@Beanpublic WxSessionManager sessionManager(){
//        OnlineWebSessionManager manager = new OnlineWebSessionManager();WxSessionManager manager = new WxSessionManager();// 加入缓存管理器manager.setCacheManager(getEhCacheManager());// 删除过期的sessionmanager.setDeleteInvalidSessions(true);// 设置全局session超时时间manager.setGlobalSessionTimeout(expireTime * 60 * 1000);// 去掉 JSESSIONIDmanager.setSessionIdUrlRewritingEnabled(false);// 定义要使用的无效的Session定时调度器manager.setSessionValidationScheduler(SpringUtils.getBean(SpringSessionValidationScheduler.class));// 是否定时检查sessionmanager.setSessionValidationSchedulerEnabled(true);return manager;}/*** 注入微信安全管理器* @return SecurityManager*/@Beanpublic SecurityManager securityManager() {// 将自定义 Realm 加进来DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(wxRealm());// 注入缓存管理器;securityManager.setCacheManager(getEhCacheManager());// session管理器securityManager.setSessionManager(sessionManager());return securityManager;}/*** 退出过滤器*/public LogoutFilter logoutFilter(){LogoutFilter logoutFilter = new LogoutFilter();logoutFilter.setCacheManager(getEhCacheManager());logoutFilter.setLoginUrl(loginUrl);return logoutFilter;}/*** Shiro过滤器配置*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// Shiro的核心安全接口,这个属性是必须的shiroFilterFactoryBean.setSecurityManager(securityManager);// 身份认证失败,则跳转到登录页面的配置shiroFilterFactoryBean.setLoginUrl(loginUrl);// 权限认证失败,则跳转到指定页面shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);// Shiro连接约束配置,即过滤链的定义LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 对静态资源设置匿名访问filterChainDefinitionMap.put("/favicon.ico**", "anon");filterChainDefinitionMap.put("/ruoyi.png**", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/docs/**", "anon");filterChainDefinitionMap.put("/fonts/**", "anon");filterChainDefinitionMap.put("/img/**", "anon");filterChainDefinitionMap.put("/ajax/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/ruoyi/**", "anon");filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");// 退出 logout地址,shiro去清除sessionfilterChainDefinitionMap.put("/logout", "logout");// 不需要拦截的访问filterChainDefinitionMap.put("/customer/getToken", "anon");filterChainDefinitionMap.put("/customer/register", "anon");filterChainDefinitionMap.put("/customer/login", "anon");filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/getTestUser", "anon");filterChainDefinitionMap.put("/getWord", "anon");// 注册相关filterChainDefinitionMap.put("/register", "anon");// 系统权限列表// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());Map<String, Filter> filters = new LinkedHashMap<String, Filter>();// 注销成功,则跳转到指定页面filters.put("logout", logoutFilter());shiroFilterFactoryBean.setFilters(filters);// 所有请求需要认证filterChainDefinitionMap.put("/**", "user");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** cookie 属性设置*/public SimpleCookie rememberMeCookie(){SimpleCookie cookie = new SimpleCookie("rememberMe");cookie.setDomain(domain);cookie.setPath(path);cookie.setHttpOnly(httpOnly);cookie.setMaxAge(maxAge * 24 * 60 * 60);return cookie;}}

三、微信和控制器

1、通过wx.login获取code,使用code到服务端换取openid和服务器返回的sessionid,注意,sessionid不要使用微信提供的“session_key”(使用微信提供的,后续很难与服务端匹配上)

return new Promise(function (resolve, reject) {wx.login({success: function (res) {if (res.code) {//登录远程服务器var code = res.code;//获取tokenutil.request(api.GetTokenUrl, { code: code }).then(function (res) {console.log(res.session_key);var session_key = res.session_key;var openid = res.openid;wx.setStorageSync('token', session_key);util.login(code, openid);console.log('=============测试开始================');setTimeout(test, 5000);})}else {reject(res);}},fail: function (err) {reject(err);}});});

2、根据返回的session,通过“wx.setStorageSync('token', session_key);”设置到全局变量,后续所有请求head都带上

/*** 封封微信的的request*/
function request(url, data = {}, method = "GET") {return new Promise(function (resolve, reject) {wx.request({url: url,data: data,method: method,header: {'Content-Type': 'application/x-www-form-urlencoded','X-Nideshop-Token': wx.getStorageSync('token')},success: function (res) {console.log("success");if (res.statusCode == 200) {if (res.data.errno == 401) {//需要登录后才可以操作// wx.showModal({//     title: '',//     content: '请先登录',//     success: function (res){//         if (res.confirm) {//             wx.removeStorageSync("userInfo");//             wx.removeStorageSync("token");//             wx.switchTab({//                 url: '/pages/ucenter/index/index'//             });//         }//     }// });} else {resolve(res.data);}} else {reject(res.errMsg);}},fail: function (err) {reject(err)console.log("failed")}})});

3、其他涉及到的注册和登录方法

/*** 调用微信登录*/
function login(code,openid) {//发起网络请求wx.request({url: api.LoginUrl,method: "GET",header: {'content-type': 'application/x-www-form-urlencoded','X-Nideshop-Token': wx.getStorageSync('token')},data: {code: code,openid: openid,session_key: wx.getStorageSync('token')},success: function (res) {console.log(wx.getStorageSync('token'));if (res.data.result == "0") {//登录失败console.log(res.data.msg);} else if (res.data.result == "2") {//新用户,先去注册register(openid);//注册完成,再次登录login();} else if (res.data.result == "1") {console.log('===========登录成功==============');}},fail: function (error) {console.log(error);}});
}/*** 使用微信openid进行注册*/
function register(openid){wx.getUserInfo({success: function (res) {var userInfo = res.userInfovar nickName = userInfo.nickNamevar avatarUrl = userInfo.avatarUrlvar gender = userInfo.gender //性别 0:未知、1:男、2:女var province = userInfo.provincevar city = userInfo.cityvar country = userInfo.countrywx.request({url: api.Register,method: "GET",header: {'Content-Type': 'application/json'},data: {openid: openid,nickName: nickName,avatarUrl: avatarUrl,gender: gender,province: province,city: city,country: country},success: function (res) {console.log('注册成功==============' + res.data.result);if (res.result == "1") {}},fail: function (error) {console.log(error);}});}})
}

4、控制器

package com.ruoyi.controller.customer;import com.alibaba.fastjson.JSONArray;
import com.mysql.cj.xdevapi.JsonArray;
import com.mysql.cj.xdevapi.JsonString;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.json.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.controller.common.CommonController;
import com.ruoyi.customer.domain.CustomerInfo;
import com.ruoyi.customer.domain.CustomerLogin;
import com.ruoyi.customer.domain.CustomerLoginLog;
import com.ruoyi.customer.service.ICustomerLoginService;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.WxSeeionObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Controller
@RequestMapping("/customer")
public class CustomerLoginController extends BaseController {private static final Logger log = LoggerFactory.getLogger(CommonController.class);@Autowiredprivate ICustomerLoginService customerLoginService;/*** 登录* @param request* @return*/@RequestMapping("getToken")@ResponseBodypublic Map<String, Object> getToken(HttpServletRequest request){String sessionid=request.getSession().getId();String code=request.getParameter("code");String result= HttpUtils.sendGet("https://api.weixin.qq.com/sns/jscode2session","appid=wx3bb68f95e5c2b2cf&secret=1a0e79d36e22ddc797c071c4e13cecc1&js_code="+code+"&grant_type=authorization_code");System.out.println(result);WxSeeionObject wxSeeionObject= JSONArray.parseObject(result,WxSeeionObject.class);Map<String, Object> map = new HashMap<String, Object>();map.put("openid",wxSeeionObject.getOpenid());map.put("session_key",sessionid);return map;}/*** 登录* @param request* @return*/@RequestMapping("login")@ResponseBodypublic Map<String, Object> login(HttpServletRequest request){String openid=request.getParameter("openid");String session_key=request.getParameter("session_key");UsernamePasswordToken token = new UsernamePasswordToken(openid, session_key, false, "wx");Subject subject = SecurityUtils.getSubject();Map<String, Object> map = new HashMap<String, Object>();try{subject.login(token);map.put("result","1");}catch (UnknownAccountException e){//新客户,需要新增注册map.put("result","2");}catch (AuthenticationException e){map.put("result","0");map.put("msg","请使用微信登录平台");}return map;}/*** 注册* @param request* @return*/@RequestMapping("register")@ResponseBodypublic Map<String, Object> register(HttpServletRequest request){String openid=request.getParameter("openid");String nickName=request.getParameter("nickName");String avatarUrl=request.getParameter("avatarUrl");String gender=request.getParameter("gender");String province=request.getParameter("province");String city=request.getParameter("city");String country=request.getParameter("country");CustomerLogin customerLogin=new CustomerLogin();customerLogin.setOpenId(openid);CustomerInfo customerInfo=new CustomerInfo();customerInfo.setNickName(nickName);customerInfo.setAvatarUrl(avatarUrl);customerInfo.setCountry(country);customerInfo.setProvince(province);customerInfo.setCity(city);customerInfo.setGender(gender);CustomerLoginLog customerLoginLog=new CustomerLoginLog();customerLoginLog.setLoginType(Byte.parseByte("1"));customerLoginService.insertCustomerLogin(customerLogin,customerInfo,customerLoginLog);Map<String, Object> map = new HashMap<String, Object>();map.put("result",1);return map;}@RequestMapping("getTestUser")@ResponseBodypublic Map<String, Object> getUser(HttpServletRequest request){Object obj=SecurityUtils.getSubject().getPrincipal();System.out.println("微信小程序正在调用。。。");Map<String, Object> map = new HashMap<String, Object>();List<String> list = new ArrayList<String>();list.add("zhangsan");list.add("lisi");list.add("wanger");list.add("mazi");map.put("list",list);System.out.println("微信小程序调用完成。。。");return map;}@RequestMapping("getWord")@ResponseBodypublic Map<String, Object> getText(String word){Map<String, Object> map = new HashMap<String, Object>();String message = "我能力有限,不要为难我";if ("后来".equals(word)) {message="正在热映的后来的我们是刘若英的处女作。";}else if("微信小程序".equals(word)){message= "想获取更多微信小程序相关知识,请更多的阅读微信官方文档,还有其他更多微信开发相关的内容,学无止境。";}else if("西安工业大学".equals(word)){message="西安工业大学(Xi'an Technological University)简称”西安工大“,位于世界历史名城古都西安,是中国西北地区唯一一所以兵工为特色,以工为主,理、文、经、管、法协调发展的教学研究型大学。原中华人民共和国兵器工业部直属的七所本科院校之一(“兵工七子”),陕西省重点建设的高水平教学研究型大学、陕西省人民政府与中国兵器工业集团、国防科技工业局共建高校、教育部“卓越工程师教育培养计划”试点高校、陕西省大学生创新能力培养综合改革试点学校。国家二级保密资格单位,是一所以\"军民结合,寓军于民\"的国防科研高校。";}map.put("message", message);return map;}@RequestMapping("")public String getText(){return "hello world";}
}

微信小程序+springboot+shiro实现登录相关推荐

  1. 微信小程序+SpringBoot实现用户登录

    微信小程序+SpringBoot实现用户登录 前言 微信小程序越来越吃香了(前话就这么多,嘿嘿) 前端 那就开始吧,登录界面就如此了 wxml内容如下,这是格式化后粘贴过来的,emmm,怪像那回事. ...

  2. 【微信小程序】shiro安全登录界面实现

    博主:

  3. 微信小程序+SpringBoot+mybatis+MySQL实现简单的登录

    微信小程序+SpringBoot+mybatis+MySQL实现简单的登录 当下微信小程序和springboot都是比较火的.今天我们来用springboot和微信小程序来实现简单的登录. 1.首先来 ...

  4. 基于微信小程序springboot粤味早茶店微信扫码点餐系统源码和论文

    这是一个功能简单的微信点餐小程序. 当今社会的发展,日新月异,发生了翻天覆地的变化,尤其是在智能方面,发展的更加迅速,随之带来的就是各个产业的智能化.军工业,化工,当然还有餐饮业,都在逐渐向智能化进发 ...

  5. 【愚公系列】2022年09月 微信小程序-微信小程序实现网页一键登录功能

    文章目录 前言 一.微信小程序实现网页一键登录功能 1.旧版登录方法 2.新版登录方法 二.相关第三方包源码 前言 如果微信小程序要获取微信登录的用户信息,需要拿到code去后台换取用户信息,具体步骤 ...

  6. 微信小程序开发之——用户登录-登录流程(1)

    一 概述 新建微信小程序自带用户登录简化 小程序登录流程时序 二 新建微信小程序自带用户登录简化 新建的微信小程序默认有用户登录功能,将多余功能去除后,简化如下 2.1 index.wxml < ...

  7. 精品微信小程序springboot居家养老服务+后台管理前后分离

    <微信小程序springboot居家养老服务+后台管理系统|前后分离VUE>该项目含有源码.文档等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后 ...

  8. [论文+辩论PPT+源码等]精品微信小程序springboot居家养老服务+后台管理前后分离

    下载:https://download.csdn.net/download/alymail/85272677 <微信小程序springboot居家养老服务+后台管理系统|前后分离VUE>该 ...

  9. 计算机实战项目 毕业设计 课程设计之 论文+辩论PPT+源码等]精品微信小程序springboot居家养老服务+后台管理前后分离

    <微信小程序springboot居家养老服务+后台管理系统|前后分离VUE>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后 ...

  10. 微信小程序+SpringBoot实现文件上传与下载

    微信小程序+SpringBoot实现文件上传与下载 1.文件上传 1.1 后端部分 1.1.1 引入Apache Commons FIleUpload组件依赖 1.1.2 设置上传文件大小限制 1.1 ...

最新文章

  1. 想读Spring源码?先从这篇「 极简教程」开始
  2. Android中下载进度条格式,Android开发如何实现文件下载进度条
  3. 八句经典座右铭必有一句适合你
  4. Oracle左右链接
  5. java List实体排序
  6. java怎么实现日程提醒_如何用java和xml实现日程提醒
  7. 三维球体换算到二维_单图像三维重建、2D到3D风格迁移和3D DeepDream
  8. docker教程,dockerfile教程
  9. python中eval函数怎么用_python3中eval函数用法简介
  10. 2021 ICCV TIMI-Net 抠图网络论文笔记
  11. 15种不用花钱就能放生的方法,你知道吗?
  12. 空格变成问号的怪问题
  13. 虚拟服务器共享文件夹禁用,虚拟机共享文件夹禁用,vm虚拟机共享文件夹
  14. 解决win10蓝牙搜索到小爱音箱无法连接问题
  15. 测线仪正确使用方法图解1
  16. 拓嘉启远电商:拼多多直通车烧钱太多的原因
  17. 2017远景能源Java面试
  18. ORACLE经验汇总
  19. 解决线程安全问题的两种办法
  20. 如何从照片中提取文字?

热门文章

  1. 面试之MySQL调优问题
  2. 湖南省工业技师学院计算机证,湖南省工业技师学院
  3. DigitalFilmTools Rays 2.1.2汉化版|丁达尔光束耶稣光滤镜插件
  4. 微信小程序的两种视频录制方式
  5. 微信小程序-视频教程-链接地址
  6. 聚类——密度聚类(DBSCAN、OPTICS、DENCLUE)
  7. 小米路由2+安装+php,小米路由器作为二级路由,完美使用APP和文件共享
  8. 个人业务网站php源码,最新个人发卡网源码,PHP运营级个人自动发卡平台完整源码...
  9. AIDA64内存与缓存测试过了算稳定吗_高频内存能带来怎样的不同!影驰HOF OC Lab Master DDR4 4000内存评测...
  10. 如何查看程序或进程调用了哪些dll文件