1.用户第一次登录/绑定,通过微信的code拿到用户的openid,存到数据库里
2.用户第二次请求,发起一个微信自动登录请求,同样传入微信的code,后台检验获取openid,检验该openid是否已经存在数据库,如果有就可以自动登录.
3.实现一个自己的MyRealm和MyOpenIdToken,主要为了能够Subject存入openid方便检验

//通过获取到自动登录的openId
        String openid = apiResult.get("openid");
        Subject subject = SecurityUtils.getSubject();
        //使用自定义realm验证openid是否已绑定用户
        WxOpenIdToken wxOpenIdToken =new WxOpenIdToken(openid);
        subject.login(wxOpenIdToken);`
  `MyOpenIdToken`:类似实体类,需要继承`UsernamePasswordToken`
  `MyRealm`:继承`AuthorizingRealm` 真正的验证逻辑在这里处理,

注意 :多个realm需要在shiro配置中配置使用策略,也可以自行百度

 缺点:因为subject中存的是openId所以登录之后还需要额外的去获取用户信息

贴一下我的代码

MyOpenIdToken.java

//MyOpenIdToken
        public class WxOpenIdToken extends UsernamePasswordToken implements Serializable {
        private String openId;
        /**
         *
         */
        private static final long serialVersionUID = 4812793519945855483L;
        @Override
        public Object getPrincipal() {
            return getOpenId();
        }

        @Override
        public Object getCredentials() {
            return "ok";
        }
        public WxOpenIdToken(String openId){
            this.openId=openId;
        }
    }

WxOpenIdRealm.java

public class WxOpenIdRealm extends AuthorizingRealm {
        @Resource
        private SysUserDao sysUserDao;
        @Resource
        private SysMenuDao sysMenuDao;

        /**
         * 授权
         * @param principals
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //TODO 用户权限列表,普通信息等...
            return info;
        }

        /**
         * 鉴权   openid 判断是否用户是否已经绑定微信
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

            String openid = (String) token.getPrincipal();
                            //sysUserDao.getbyWxaOpenId 根据openid查询是否有已绑定的userid,有就时已绑定
            SysUserEntity exUser = sysUserDao.getbyWxaOpenId(openid);
            if (exUser != null) {
                AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(openid, "ok", this.getClass().getSimpleName());
                return authcInfo;
            } else {
                return null;
            }
        }
    }

ShiroConfig.java 注入两个realm并设置验证策略

@Bean
public UserRealm userRealm(){
    UserRealm userRealm = new UserRealm();
    //账号密码登录使用realm
    return userRealm;
}

@Bean
public WxOpenIdRealm wxCodeRealm(){
    WxOpenIdRealm wxOpenIdRealm = new WxOpenIdRealm();
    //小程序使用openid登录使用的realm
    return wxOpenIdRealm;
}
          /**
     * 系统自带的Realm管理,主要针对多realm
     * */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator() {
        ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        //只要有一个成功就视为登录成功
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }

不只是微信小程序,同样的还有app登录,手机短信验证码都可以自定义realm验证



由于本人第一次使用微信小程序配合 Shiro 做验权,
发现小程序不能像普通网页那样做验权,
后台 Shiro 根本识别不到小程序客户端的状态

原因
原来是小程序不自带 cookie 的管理,导致 Shiro 下发的 SessionId,
再小程序下次请求时,不会带上之前的 SessionId
解决方案
自己手动存储 cookie ,并在所有请求中带上 cookie
这是最简单粗暴的方法之一
(当然,也可以去自定义 Shiro 的 Session 管理,等等其他方法)

第一次登录请求时,保存 cookie

http(post, "/api/wx/login", {
  code,
}).then((response) => {
  wx.setStorageSync("sessionId", response.header["Set-Cookie"]);

  wx.navigateBack();
});

之后发送请求时,都带上 cookie

const http = (method, url, data) => {
  let header;

  // 将存储的 cookie 带上
  if (wx.getStorageSync("sessionId")) {
    header = {
      "content-type": "application/x-www-form-urlencoded",
      cookie: wx.getStorageSync("sessionId"),
    };
  }

  return new Promise((resolve, reject) => {
    wx.request({
      data,
      method,
      url: `${host}${url}`,
      header,
      dataType: "JSON",
      success: (response) => {
        let statusCode = response.statusCode;
      },
      fail: (errors) => {
        wx.showToast({ title: "请求失败", icon: "none" });
        reject(errors);
      },
    });
  });
};
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐