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);
},
});
});
};