在shiro中控制自动登录

场景一:集群中各节点登录状态保持一致,当然这个集群没有统一的认证中心
场景二:微信环境微店项目,自动登录,进入微店,则判断用户是否注册,如果已经注册则自动登录否则跳转到注册页面(ps:需要用户关注公众号才可以注册)

这儿针对场景二开展
在shiro中自定义过滤器authcUser和tryLogin
authcUser 只有登录才可以访问当前路径,没有登录则尝试自动登录,登录失败跳转到注册loginUrl指向的页面
tryLogin 不需要登录也可以访问,如果没有登录则尝试自动登录

其实本来使用Servlet的Filter实现的,结果发现有点问题所以换成了shiro实现

spring-shiro.xml的部分配置文件
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
        <property name="loginUrl" value="${http.domain.ssl}/register" />
        <!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) -->
        <!-- <property name="successUrl" value="/" ></property> -->
        <!-- 用户访问未对其授权的资源时,所显示的连接 -->
        <property name="unauthorizedUrl" value="/error/unauthorized" />
        <property name="filters">
            <map>
                <entry key="authcUser" >
                    <bean class="com.shiro.filter.AuthenticationFilter"></bean>
                </entry>
                <entry key="tryLogin">
                    <bean class="com.shiro.filter.AnonAndTryLoginFilter"></bean>
                </entry>
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /my/comeshare = anon
                /my/share = anon
                /my/* = authcUser
                /team/* = authcUser
                /** = tryLogin
            </value>
        </property>
    </bean>
自定义的BaseFilter
public abstract class AutoLoginBaseFilter extends org.apache.shiro.web.filter.authc.AuthenticatingFilter{

    Logger log = LoggerFactory.getLogger(AutoLoginBaseFilter.class);
    @Autowired
    protected UserProcess userProcess;
    @Autowired
    protected IismsWxSubscribeInfoService subscribeInfoService;

    @Override
    protected AuthenticationToken createToken(ServletRequest request,
            ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest)request;
        //从请求的session中获取openId
        String openId = SecurityHelper.getOpenIdFromRequest(req);
        if (!StringUtils.isBlank(openId)) {
            IsmsWxSubscribeInfo wxSubscribeInfo = subscribeInfoService.selectSubscribeInfoByOpenId(openId);
            IsmsCusUserInfo user = userProcess.getByOpenId(openId);
            //如果用户已经关注切是注册状态则创建Token
            if (wxSubscribeInfo != null && "1".equals(wxSubscribeInfo.getActionType()) 
                    && RegisterStatusEnum.YES.getValue().equals(user.getRegisterStatus())) {
                return new UsernamePasswordToken(user.getMobilePhone(), user.getPassword());
            }
        }
        return null;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest arg0, ServletResponse arg1)
            throws Exception {
        return false;
    }

    /**
     * 尝试自动登录
     * 关注微信且用户状态是未注册的才可以登录成功
     * 
     * @param request
     * @param response
     * @return true 登录成功 否则失败
     */
    @SuppressWarnings("deprecation")
    public boolean tryLogin(ServletRequest request, ServletResponse response) {
        ApiErrorCodeEnum result = ApiErrorCodeEnum.USER_0018;
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        String openId = SecurityHelper.getOpenIdFromRequest(req);
        //关注微信且用户状态是未注册的才可以登录成功
        if (!StringUtils.isBlank(openId) && !SecurityUtils.getSubject().isAuthenticated()) {
            IsmsWxSubscribeInfo wxSubscribeInfo = subscribeInfoService.selectSubscribeInfoByOpenId(openId);
            IsmsCusUserInfo user = userProcess.getByOpenId(openId);
            if (wxSubscribeInfo != null && "1".equals(wxSubscribeInfo.getActionType()) 
                    && RegisterStatusEnum.YES.getValue().equals(user.getRegisterStatus())) {
                //尝试自动登录
                result = userProcess.login(user.getId(), user.getPassword(), req, res);
            }
        }
        return result == null;
    }

}
//定义过滤器,不需要登录即可访问,在这个过滤器中尝试去登录,即使登录不成功也通过
public class AnonAndTryLoginFilter extends AutoLoginBaseFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request,
            ServletResponse response, Object mappedValue) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            tryLogin(request, response);
        }
        return true;
    }
}
//定义过滤器,如果没有登录自动登录,登录成功则通过否则跳转到注册页面
public class AuthenticationFilter extends AutoLoginBaseFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request,
            ServletResponse response, Object mappedValue) {
        boolean authed = SecurityUtils.getSubject().isAuthenticated();
        if (!authed) {
            // 如果已经注册的用户,肯定能自动登录成功,登陆不成功则肯定没有注册
            tryLogin(request, response);
        }
        authed = SecurityUtils.getSubject().isAuthenticated();
        try {
            if (!authed) {
                //没有注册的用户引导去注册页面
                org.apache.shiro.web.util.WebUtils.issueRedirect(request, response, getLoginUrl());
            }
        } catch (IOException e) {
        }
        return authed;
    }
}
//UserProcess 中的login方法,自动登录的关键代码
PrincipalCollection principals = new SimplePrincipalCollection(user.getId(), "MobileRealm");    
Builder builder = new WebSubject.Builder(request, response);    
builder.principals(principals);    
builder.authenticated(true);    
WebSubject subject = builder.buildWebSubject();    
ThreadContext.bind(subject);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值