如何更正 Shiro 注销代码(用户在注销后仍然可以访问页面)?

时间:2021-07-17 20:47:50

标签: java authentication shiro

我正在实施 Shiro 安全性并且我的登录实施正在运行,但注销似乎没有注销用户。我有一个注销链接,它指向一个调用 Shiro 注销代码的自定义 servlet。代码执行(我可以单步执行代码并且在控制台中可以看到日志输出)但是,如果我按下浏览器中的后退按钮并重新加载原始页面,我可以到达该页面并且不会要求我重新-输入我的登录凭据。

我需要做什么来解决这个问题?

servlet 代码如下所示。完整的例子在这里:

https://github.com/NACHC-CAD/web-security-example

Servlet 代码:

[...[pk1], ...[pk2]]

登录代码:

[d1[pk1], d2[pk2]]

web.xml

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Subject subject = SecurityUtils.getSubject();
    log.info("Doing log off for user: ");
    if(subject != null && subject.isAuthenticated()) {
        subject.logout();
        log.info("Subject has been logged off");
    } else {
        log.info("USER NOT FOUND, NOT LOGGED OFF");
    }
    log.info("User has been log offed");
}

shiro.ini

@Slf4j
public class MyAppRealm extends SimpleAccountRealm {

    /**
     * Authentication method is based on SimpleAccountRealm doGetAuthenticationInfo(AuthenticationToken token) method.  
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        log.info("* * * DOING CUSTOM AUTHN * * *");
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String uid = upToken.getUsername();
        String pwd = new String(upToken.getPassword());
        log.info("Doing login for user: " + uid);
        SimpleAccount account = null;
        if(uid.equals("foo") && pwd.equals("bar")) {
            account = new SimpleAccount("foo", "bar", getName());
            account.setCredentials("bar");
            account.addRole("ROLE_ADMIN");
        } else {
            account = null;
            log.info("Credentials failed for user: " + uid);
        }
        // account.setObjectPermissions(permissions);
        log.info("Done with custom authn");
        return account;
    }

    /**
     * Authorization method is based on SimpleAccountRealm doGetAuthorizationInfo(PrincipalCollection principals) method.  
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("* * * DOING CUSTOM AUTHZ * * *");
           String username = getUsername(principals);
            USERS_LOCK.readLock().lock();
            try {
                SimpleAccount rtn = this.users.get(username);
                log.info("Done with custom authz.");
                return rtn;
            } finally {
                USERS_LOCK.readLock().unlock();
            }       
    }

}

--- 编辑---------------------------

看起来浏览器正在缓存凭据并在访问同一页面时重新发送。即使从新选项卡中的隐身窗口,如果我访问同一页面,浏览器也会将基本身份验证凭据添加到请求中。看起来这是由 Chrome 添加的,作为他们对基本身份验证的标准处理的一部分。更多信息请点击此处:How to clear basic authentication details in chrome(用于清除详细信息的方法非常手动且依赖于用户,如果您需要确保已注销的用户需要重新提供凭据,则不太适合)。

--- 编辑 2 -----------------

根据下面接受的答案的建议,我能够通过使用 Shiro 实现基于表单的身份验证来解决这个问题。完整示例在这里:

https://github.com/NACHC-CAD/web-security-example

enter image description here

1 个答案:

答案 0 :(得分:1)

这是 BASIC 身份验证的常见问题。

您是否需要支持 BASIC 身份验证?如果没有,您可以使用登录表单,请参阅此处的示例:https://github.com/apache/shiro/blob/main/samples/web/src/main/webapp/WEB-INF/shiro.ini#L54-L60

如果您需要同时支持 BASIC 身份验证和 Web 浏览器表单,您可以执行以下操作:

/app/** = authcBasic[permissive], authc

注意:这是来自记忆,所以相应地测试;)