Shiro学习笔记(二)UsernamePasswordToken源码简单解析

在shrio中,AuthenticationToken用于存储前端传来的登录信息,通俗来说就是用户名及密码等。而在这之中比较常用的就是UsernamePasswordToken。为了了解shrio的验证过程有必要先了解与验证相关的主要的几个类。首先看下shrio对UsernamePasswordToken的描述:

/**
 * <p>A simple username/password authentication token to support the most widely-used authentication mechanism.  This
 * class also implements the {@link RememberMeAuthenticationToken RememberMeAuthenticationToken} interface to support
 * &quot;Remember Me&quot; services across user sessions as well as the
 * {@link org.apache.shiro.authc.HostAuthenticationToken HostAuthenticationToken} interface to retain the host name
 * or IP address location from where the authentication attempt is occurring.</p>
 * <p/>
 * <p>&quot;Remember Me&quot; authentications are disabled by default, but if the application developer wishes to allow
 * it for a login attempt, all that is necessary is to call {@link #setRememberMe setRememberMe(true)}.  If the underlying
 * <tt>SecurityManager</tt> implementation also supports <tt>RememberMe</tt> services, the user's identity will be
 * remembered across sessions.
 * <p/>
 * <p>Note that this class stores a password as a char[] instead of a String
 * (which may seem more logical).  This is because Strings are immutable and their
 * internal value cannot be overwritten - meaning even a nulled String instance might be accessible in memory at a later
 * time (e.g. memory dump).  This is not good for sensitive information such as passwords. For more information, see the
 * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx">
 * Java Cryptography Extension Reference Guide</a>.</p>
 * <p/>
 * <p>To avoid this possibility of later memory access, the application developer should always call
 * {@link #clear() clear()} after using the token to perform a login attempt.</p>
 *
 * @since 0.1
 */
public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {

这段注释对UsernamePasswordToken这个类做了十分详尽的说明。UsernamePasswordToken是一个简单的包含username及password即用户名及密码的登录验证用token,这个类同时继承了HostAuthenticationToken及RememberMeAuthenticationToken,因此UsernamePasswordToken能够存储客户端的主机地址以及确定token是否能够被后续的方法使用。值得注意的是在这里password是以char数组的形式存储的,这样设计是因为String本身是不可变的,这可能会导致无效的密码被访问到。另外,开发者应在验证之后调用clear方法清除token从而杜绝该token在后续被访问的可能性。

UserNamePasswordToken类的主要属性如下及用户名,密码,是否记住token以及验证来源的host主机地址:

    /**
     * The username
     */
    private String username;

    /**
     * The password, in char[] format
     */
    private char[] password;

    /**
     * Whether or not 'rememberMe' should be enabled for the corresponding login attempt;
     * default is <code>false</code>
     */
    private boolean rememberMe = false;

    /**
     * The location from where the login attempt occurs, or <code>null</code> if not known or explicitly
     * omitted.
     */
    private String host;

获取token的用户名

    /**
     * Simply returns {@link #getUsername() getUsername()}.
     *
     * @return the {@link #getUsername() username}.
     * @see org.apache.shiro.authc.AuthenticationToken#getPrincipal()
     */
    public Object getPrincipal() {
        return getUsername();
    }
    /**
     * Returns the username submitted during an authentication attempt.
     *
     * @return the username submitted during an authentication attempt.
     */
    public String getUsername() {
        return username;
    }

一般来说,我们会通过调用getPrincipal()方法来获取token中的用户名并以此来进行登录验证而本方法的实质就是通过调用本地getUserName()方法直接获取存储在token中的username。

获取token的密码

    /**
     * Returns the {@link #getPassword() password} char array.
     *
     * @return the {@link #getPassword() password} char array.
     * @see org.apache.shiro.authc.AuthenticationToken#getCredentials()
     */
    public Object getCredentials() {
        return getPassword();
    }
    /**
     * Returns the password submitted during an authentication attempt as a character array.
     *
     * @return the password submitted during an authentication attempt as a character array.
     */
    public char[] getPassword() {
        return password;
    }

一般来说我们通过getCredentials()方法来获取token中的密码,该方法与获取用户名的方式一致,调用本地getPassword()方法获取存储在token中的密码。

Clear方法

    /**
     * Clears out (nulls) the username, password, rememberMe, and inetAddress.  The password bytes are explicitly set to
     * <tt>0x00</tt> before nulling to eliminate the possibility of memory access at a later time.
     */
    public void clear() {
        this.username = null;
        this.host = null;
        this.rememberMe = false;

        if (this.password != null) {
            for (int i = 0; i < password.length; i++) {
                this.password[i] = 0x00;
            }
            this.password = null;
        }

    }

为了防止验证完成后的后续访问,我们应在验证完成后调用clear方法清除token中数据,这里需要注意的是UsernamePasswordToken类在clear()方法中对password做了处理而不是单纯地将password的引用置null,这里首先将password引用对应的char数组的值全部置0然后再将引用断开。这里我的理解是虽然JVM会调用GC将不可达的根节点的对象回收,但是GC本身是不定时的即不是实时清除垃圾对象,因此在这里为了防止password在被GC清除前仍能被访问到,这里将char数组里的值全部置0从而根本上杜绝非法访问。

toString()方法

    /**
     * Returns the String representation.  It does not include the password in the resulting
     * string for security reasons to prevent accidentally printing out a password
     * that might be widely viewable).
     *
     * @return the String representation of the <tt>UsernamePasswordToken</tt>, omitting
     *         the password.
     */
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getName());
        sb.append(" - ");
        sb.append(username);
        sb.append(", rememberMe=").append(rememberMe);
        if (host != null) {
            sb.append(" (").append(host).append(")");
        }
        return sb.toString();
    }

这里没什么好说的,创建一个StringBuilder对象将用户名等信息拼接起来并返回。注意为了安全起见这里不会将密码拼接进返回的String中。

  • 25
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Shiro中,判断session是否失效可以通过以下代码实现: ```java Subject subject = SecurityUtils.getSubject(); if (subject != null) { Session session = subject.getSession(false); if (session == null) { // session已经失效 } } ``` 上述代码中,首先通过`SecurityUtils.getSubject()`获取`Subject`对象,再通过`subject.getSession(false)`获取当前用户的`Session`对象,如果返回值为`null`,则表示`Session`已经失效。 当然,也可以通过在Shiro配置文件中配置`sessionManager`,设置`sessionValidationSchedulerEnabled`参数为`true`,开启Shiro的`Session`定期检查功能,实现自动检测`Session`是否失效。 另外,在Spring Boot中集成Shiro时,可以通过实现`SessionListener`接口,监听`Session`的创建、销毁和过期事件,并在事件触发时执行相应的操作。具体可参考以下代码示例: ```java @Component public class MySessionListener implements SessionListener { @Override public void onStart(Session session) { // Session创建时触发 } @Override public void onStop(Session session) { // Session销毁时触发 } @Override public void onExpiration(Session session) { // Session过期时触发 } } ``` 在以上代码中,实现了`SessionListener`接口,并在各个方法中编写相应的操作代码,以实现对`Session`的监听。最后,在Spring Boot配置文件中配置`shiro.sessionListeners`参数,将自定义的`SessionListener`注册到Shiro中即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值