简体   繁体   English

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

[英]How to correct Shiro logout code (user can still access pages after log out is executed)?

I'm implementing Shiro security and my login implementation is working but logoff seems to not log off the user.我正在实施 Shiro 安全性并且我的登录实施正在运行,但注销似乎没有注销用户。 I have a log off link that points to a custom servlet the calls the Shiro logoff code.我有一个注销链接,它指向一个调用 Shiro 注销代码的自定义 servlet。 The code executes (I can step through the code and the logging output is seen in the console) however, if I press the back button in the browser and reload the original page I can get to the page and I am not asked to re-enter my logon credentials.代码执行(我可以单步执行代码并且在控制台中可以看到日志输出)但是,如果我按下浏览器中的后退按钮并重新加载原始页面,我可以到达该页面并且不会要求我重新-输入我的登录凭据。

What do I need to do to fix this?我需要做什么来解决这个问题?

The servlet code is shown below. servlet 代码如下所示。 The complete example is here:完整的例子在这里:

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

Servlet code:服务端代码:

@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");
}

Logon code:登录代码:

@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();
            }       
    }

}

web.xml网页.xml

<!-- 
*
* shiro stuff
*
-->

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

shiro.ini设置文件

# ---
#
# ini file for shiro
#
# ---

[main]
myRealm = org.nachc.examples.websecurity.shiro.util.realm.MyAppRealm
securityManager.realms = $myRealm

[users]
admin = admin, ROLE_ADMIN

[roles]
ROLE_ADMIN = *

[urls]
/app/** = authcBasic

--- EDIT --------------------------- - - 编辑 - - - - - - - - - - - - - -

It looks like the browser is caching the credentials and resending if the same page is accessed.看起来浏览器正在缓存凭据并在访问同一页面时重新发送。 Even from an incognito window in a new tab, if I access the same page the basic authentication credentials are added to the request by the browser.即使从新选项卡中的隐身窗口,如果我访问同一页面,浏览器也会将基本身份验证凭据添加到请求中。 It looks like this is add by Chrome as part of their standard handling of basic authentication.看起来这是由 Chrome 添加的,作为他们对基本身份验证的标准处理的一部分。 More info here: How to clear basic authentication details in chrome (the methods given to clear the details is very manual and user dependent, not really suitable if you have a requirement to ensure a logged off user needs to resupply credentials).此处的更多信息: 如何清除 chrome 中的基本身份验证详细信息(提供的清除详细信息的方法非常手动且依赖于用户,如果您需要确保已注销的用户需要重新提供凭据,则不太适合)。

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

I was able to get around this problem by implementing form based authentication using Shiro per the suggestions of the accepted answer below.根据下面接受的答案的建议,我能够通过使用 Shiro 实现基于表单的身份验证来解决这个问题。 Complete example is here:完整的例子在这里:

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

在此处输入图片说明

This is a common problem with BASIC auth.这是 BASIC 身份验证的常见问题。

Do you need to support BASIC auth?你需要支持 BASIC auth 吗? If not, you could use a login form, see the example from here: https://github.com/apache/shiro/blob/main/samples/web/src/main/webapp/WEB-INF/shiro.ini#L54-L60如果没有,您可以使用登录表单,请参阅此处的示例: https : //github.com/apache/shiro/blob/main/samples/web/src/main/webapp/WEB-INF/shiro.ini# L54-L60

If you need to support both a BASIC auth and a form for web browsers, you could do something like:如果您需要同时支持 BASIC 身份验证和 Web 浏览器表单,您可以执行以下操作:

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

NOTE: This is from memory, so test accordingly ;)注意:这是从记忆中得出的,因此请相应地进行测试;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM