如何记录 Shiro 输出?

Posted

技术标签:

【中文标题】如何记录 Shiro 输出?【英文标题】:How to log Shiro output? 【发布时间】:2021-09-06 04:54:59 【问题描述】:

试图弄清楚为什么我在 log4j.properties 中描述的日志文件中看不到来自 shiro 的日志消息。下面代码中显示的所有日志消息都记录在日志文件中,但我没有看到来自 shiro 的任何内容。不知道我应该看到什么。任何建议将不胜感激。

详情:

使用 log4j-1.2.17 记录应用程序日志消息。 使用 shiro-1.2.6 登录用户。 使用 slf4j-log4j12-1.7.9 让 shiro 与 log4j 对话。 使用 java 8。

请参阅以下详细信息:

log4j.properties 的内容 包含的库 shiro 登录代码

log4j.properties

# Do not inherit appenders from the root logger.
log4j.additivity.default=false

# Set root logger level and attach zero or more appenders.
log4j.rootLogger=DEBUG, file

# Set up the file appender.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.Name=Logger
log4j.appender.file.File=/path-to-log-file/App.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=25
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-6p%dDATE - %C1.%M:%L - %m%n

# Default Shiro logging
log4j.logger.org.apache.shiro=TRACE
log4j.logger.org.apache.shiro.realm.text.PropertiesRealm=TRACE
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=TRACE
log4j.logger.org.apache.shiro.io=TRACE
log4j.logger.org.apache.shiro.web.servlet=TRACE
log4j.logger.org.apache.shiro.util.ThreadContext=TRACE

构建路径中的库列表:

调用shiro登录用户的代码:

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.hibernate.Query;
import org.hibernate.Session;

...

Subject newUser = SecurityUtils.getSubject();
// The username and password authentication token. Set rememberMe to false
UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray(), false);
// Retrieve the login principal
String loginPrincipal = (String) token.getPrincipal();

logger.info("*** SERVER: Before SHIRO login.");
logger.info("*** SERVER: loginBean.getUser: " + loginBean.getUserId());
logger.info("*** SERVER: newUser.getSession(): " + newUser.getSession().getId());

// Use the security manager to log in
//It calls UniquePrincipalSecurityManager, which extends DefaultWebSecurityManager
SecurityUtils.getSecurityManager().login(newUser, token);

logger.info("*** SERVER: After SHIRO login.");
logger.info("*** SERVER: newUser.getSession(): " + newUser.getSession().getId());
logger.info("*** SERVER: Logged-In Users (after login event): " + getLoggedInUsers().toString());

...

public class UniquePrincipalSecurityManager extends DefaultWebSecurityManager 

    private static Logger logger = ServerLogging.getServerLogger();

    /**
     * Validates that the user can log into the session and calls Shiro for Login.
     * 
     * @return The subject. Null if not authenticated.
     */
    @Override
    public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException 
        // Retrieve the login principal
        String loginPrincipal = (String) token.getPrincipal();

        // The final Subject to return
        Subject returnedSubject = null;

        try 
            // Ensure the session is available and that the user can log in
            validateCanLogIntoSession(subject, loginPrincipal);

            logger.info("*** SERVER: Passed validateCanLogIntoSession");

            // Call Shiro for login
            returnedSubject = super.login(subject, token);

            if (returnedSubject != null) 
                logger.info("*** SERVER: loginPrincipal: " + loginPrincipal);
                logger.info("*** SERVER: returnedSubject.getPrincipal(): "
                    + returnedSubject.getPrincipal().toString());
                logger.info("*** SERVER: returnedSubject.getSession(): "
                    + returnedSubject.getSession().getId());
                logger.info("*** SERVER: returnedSubject.isAuthenticated(): "
                    + returnedSubject.isAuthenticated());

             else 
                logger.info("*** SERVER: Login Failed: " + loginPrincipal);
            
         catch (AuthenticationException ex) 
            logger.info("*** SERVER: Login Failed: " + loginPrincipal);

            // Something went wrong with the authentication, let the caller deal with it.
            throw ex;
        
        return returnedSubject;
    

【问题讨论】:

【参考方案1】:

Shiro 使用 SLF4J,这意味着 Shiro 实际上并不直接记录任何内容,或者控制如何为您的应用程序配置日志。这是目前最流行的 Java Logging 框架之一,因此我建议您花点时间阅读一下。

SLF4J

TL;DR 是库和框架依赖于slf4j-api,并且您的应用程序提供了实际的日志记录实现,例如slf4j-log4j12。所有实际的日志配置都是通过 log4j 完成的。

突出的一件事是您正在混合和匹配 SLF4J 版本,这是您不应该做的(并且可能是您看到的问题的一部分)。

还有一点需要指出,您可能已经注意到了,但是手动管理依赖项非常困难(旧的签入 jar 文件方法),Maven 和 Gradle 等工具简化了这些问题,或者如果您使用的是 Ant ,你可以使用Ivy。

【讨论】:

以上是关于如何记录 Shiro 输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Apache Shiro 中定义属性级权限

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

shiro 内存马如何连接

我的shiro之旅: 十二 shiro 踢出用户(同一用户只能一处登录)

Shiro:Spring-boot如何集成Shiro(上)

如何使用Shiro