前言
说明一下需求,最近做的平台,有多张用户表,怎么根据不同用户登录去执行自己查询不同数据库并实现认证的业务逻辑呢?
博主参与的产品开发进入阶段性完成期,有时间将过程中遇到的相关问题一一总结。
总结
实现本需求,首先是从Subject入手,它是完成shiro登录过程的入口,login(UsernamePasswordToken)方法完成用户名密码传递,后面自己实现Realm去认证登录,关键就在如何区分这些用户名密码是对应哪个数据库表,若有一个状态去判断它们,则可以解决问题。
设计上的反思
其实从实际参与这个大产品开发之后,越来越发现,它不便于我们对各类用户的管理,虽然做了很多针对shiro的扩展去实现自己想要的功能,但渐渐明白为什么shiro不提供这样的解决方案。
这里,博主也建议,用户表可以有多个,但登录认证的表其实只保留一个就好,将你的多Realm抽象出来一个关系表映射,将各种状态加入,登录等认证交由统一维护,具体信息查询等封装抽象,下面做对应实现即可,这样才应该是跨平台的,以后也只需要存储跟别的平台的用户关系绑定,就完成了登录。
正文
shiro标准的登录过程是用户在Controller里创建UsernamePasswordToken对象,然后绑定上前端访问过来的账号密码,之后由Subject.login(UsernamePasswordToken)完成登录,自己实现AuthorizingRealm完成登录认证,里面插入操作Service、DAO代码;(业务代码省略)
———-
若要区分不同用户登录查询哪个表,若有3个用户表,那么对于Service、DAO应该是有3种不同的代码片,毕竟业务不同,绑定字段不同,查询数据库表不同。如此,在最开始阶段,用户登录时,我们需要标记登录去查哪个表,标记后让系统动态处理,创建一个枚举或者静态常量类都行:
public class UserType {
/** 经销商平台 */
public static final String AGENCY = "agency";
/** 厂商平台 */
public static final String FACTORY = "factory";
/** 系统平台 */
public static final String SYSTEM = "system";
/** 消费者平台 */
public static final String PERSON = "person";
/** 游客 */
public static final String GUEST = "guest";
}
接下来扩展UsernamePasswordToken
,让其携带我们上面加的类型到Realm认证中,这样才便于判断用户类型:
/**
* Description:自定义shiro-token重写类,用于多类型用户校验
* @author around
* @date 2017年8月15日上午9:50:42
*/
public class CustomLoginToken extends UsernamePasswordToken {
private static final long serialVersionUID = 2020457391511655213L;
private String loginType;
public CustomLoginToken() {}
public CustomLoginToken(final String username, final String password,
final String loginType) {
super(username, password);
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
如此,后面我们在用户登录时,不再调用系统的UsernamePasswordToken类绑定用户密码,而是调用CustomLoginToken进行绑定,并且还可以多携带参数loginType。
———-
接下来完成登录操作,shiro是需要用户自行去访问对应数据库(它也不知道访