shiro不加入rememberMe没事,一加入就出错.

RememberMeAuthenticationToken :

public interface RememberMeAuthenticationToken extends AuthenticationToken {

    /**
* Returns {@code true} if the submitting user wishes their identity (principal(s)) to be remembered
* across sessions, {@code false} otherwise.
*
* @return {@code true} if the submitting user wishes their identity (principal(s)) to be remembered
* across sessions, {@code false} otherwise.
*/
boolean isRememberMe(); }

该接口只有一个isRememberMe() 来判定是否选定了记住我选项.

UsernamePasswordToken : 该类实现了RememberMeAuthenticationToken

public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken
/**
* Whether or not 'rememberMe' should be enabled for the corresponding login attempt;
* default is <code>false</code>
*/
private boolean rememberMe = false;

默认参数false,

/**
* Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user
* wishes their identity to be remembered across sessions.
* <p/>
* <p>This is a convience constructor and maintains the password internally via a character
* array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a String
* in your code could have possible security implications as noted in the class JavaDoc.</p>
*
* @param username the username submitted for authentication
* @param password the password string submitted for authentication
* @param rememberMe if the user wishes their identity to be remembered across sessions
* @since 0.9
*/
public UsernamePasswordToken(final String username, final String password, final boolean rememberMe) {
this(username, password != null ? password.toCharArray() : null, rememberMe, null);
}

里面的可以传入rememberMe的一个构造器,最后一个null是host

/**
* Simply returns {@link #getUsername() getUsername()}.
*
* @return the {@link #getUsername() username}.
* @see org.apache.shiro.authc.AuthenticationToken#getPrincipal()
*/
public Object getPrincipal() {
return getUsername();
}
/**
* 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();
}

这些晦涩的getPricipal(), getCredentials()其实就是获取用户名,密码的Object表示

登录的一个方法 (控制层)

 @RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(Model model, User user,boolean rememberMe) {
System.err.println("login");
System.err.println("rememberMe:"+rememberMe);
// UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword());
System.err.println("rememberMe:"+rememberMe);
UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword(), rememberMe);
Subject subject = SecurityUtils.getSubject(); try {
subject.login(token);
} catch (AuthenticationException e) {
// e.printStackTrace();
System.err.println("login异常");
}
Session session = subject.getSession();
session.setAttribute("subject",subject);
return "redirect:/admin/";//该路径应该为后台的首页页面,为login之后的redirect路径
}

可以看出来调用了构造器UsernamePasswordToken,传入三个参数,分别是前端form过来的name,password,rememberMe,

但是会报异常.

2019-01-17 15:51:10,281 - Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - null, 
rememberMe=false (0:0:0:0:0:0:0:1)]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException).

这表示身份验证失败了,但是报错之后又查询数据库还是会通过登录.这就奇怪了.

如果只是传入name,password,没有错.

将身份验证信息方法改为数据库里的用户名(写死)

/*获取身份验证信息*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取账号密码
// Object userName = token.getPrincipal();
// String userName = token.getPrincipal().toString();
// 获取数据库中的密码
User user = userService.getByName("zhang3");
String passwordInDB = user.getPassword();
String salt = user.getSalt();
// 认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
// 盐也放进去
// 这样通过applicationContext-shiro.xml里配置的 HashedCredentialsMatcher 进行自动校验
SimpleAuthenticationInfo a = new SimpleAuthenticationInfo("zhang3", passwordInDB, ByteSource.Util.bytes(salt),
getName());
return a;
}

竟然登录成功了.

可以看到时间也是设置的30天.

/**
* cookie对象,会话Cookie模板,默认为:JSESSIONID
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
simpleCookie.setHttpOnly(true);
simpleCookie.setPath("/admin/**");
simpleCookie.setMaxAge(60*60*24*30);//一个月cookie保留时间
return simpleCookie;
}

继续测试

现在是没有rememberMe这个session的,因为还没登录.

当不选择记住我时,

当选择了记住我时,除了有上面这个,还有,

也就是说rememberMe功能实现了,那么获取名称当时为什么会报空指针异常?

将数据改回来,肯定是依旧报错,但是用户名不能写死,那是不是当UsernamePasswordToken转换为AuthenticationToken出错的呢?

在AuthenticationToken中,不存在对rememberMe的参数判定和其它方法,那么能不能直接对

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.authc; import java.io.Serializable; /**
* <p>An <tt>AuthenticationToken</tt> is a consolidation of an account's principals and supporting
* credentials submitted by a user during an authentication attempt.
* <p/>
* <p>The token is submitted to an {@link Authenticator Authenticator} via the
* {@link Authenticator#authenticate(AuthenticationToken) authenticate(token)} method. The
* Authenticator then executes the authentication/log-in process.
* <p/>
* <p>Common implementations of an <tt>AuthenticationToken</tt> would have username/password
* pairs, X.509 Certificate, PGP key, or anything else you can think of. The token can be
* anything needed by an {@link Authenticator} to authenticate properly.
* <p/>
* <p>Because applications represent user data and credentials in different ways, implementations
* of this interface are application-specific. You are free to acquire a user's principals and
* credentials however you wish (e.g. web form, Swing form, fingerprint identification, etc) and
* then submit them to the Shiro framework in the form of an implementation of this
* interface.
* <p/>
* <p>If your application's authentication process is username/password based
* (like most), instead of implementing this interface yourself, take a look at the
* {@link UsernamePasswordToken UsernamePasswordToken} class, as it is probably sufficient for your needs.
* <p/>
* <p>RememberMe services are enabled for a token if they implement a sub-interface of this one, called
* {@link RememberMeAuthenticationToken RememberMeAuthenticationToken}. Implement that interfac if you need
* RememberMe services (the <tt>UsernamePasswordToken</tt> already implements this interface).
* <p/>
* <p>If you are familiar with JAAS, an <tt>AuthenticationToken</tt> replaces the concept of a
* {@link javax.security.auth.callback.Callback}, and defines meaningful behavior
* (<tt>Callback</tt> is just a marker interface, and of little use). We
* also think the name <em>AuthenticationToken</em> more accurately reflects its true purpose
* in a login framework, whereas <em>Callback</em> is less obvious.
*
* @see RememberMeAuthenticationToken
* @see HostAuthenticationToken
* @see UsernamePasswordToken
* @since 0.1
*/
public interface AuthenticationToken extends Serializable { /**
* Returns the account identity submitted during the authentication process.
* <p/>
* <p>Most application authentications are username/password based and have this
* object represent a username. If this is the case for your application,
* take a look at the {@link UsernamePasswordToken UsernamePasswordToken}, as it is probably
* sufficient for your use.
* <p/>
* <p>Ultimately, the object returned is application specific and can represent
* any account identity (user id, X.509 certificate, etc).
*
* @return the account identity submitted during the authentication process.
* @see UsernamePasswordToken
*/
Object getPrincipal(); /**
* Returns the credentials submitted by the user during the authentication process that verifies
* the submitted {@link #getPrincipal() account identity}.
* <p/>
* <p>Most application authentications are username/password based and have this object
* represent a submitted password. If this is the case for your application,
* take a look at the {@link UsernamePasswordToken UsernamePasswordToken}, as it is probably
* sufficient for your use.
* <p/>
* <p>Ultimately, the credentials Object returned is application specific and can represent
* any credential mechanism.
*
* @return the credential submitted by the user during the authentication process.
*/
Object getCredentials(); }

再次测试中,可以获取name,but...还是空指针异常.

但是奇怪的是,一直有rememberMe 30day的cookie存在...

可以看到

public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
public interface HostAuthenticationToken extends AuthenticationToken {

也就是说明了为什么可以将UsernamePasswordToken类型的token传入到AuthenticationToken的参数中了

最终决定采用捕获异常来处理.奇葩的是能获取名称的同时会报null异常:

zhang3
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b18608c] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@584114076 wrapping com.mysql.cj.jdbc.ConnectionImpl@6f6a65e9] will not be managed by Spring
==> Preparing: select 'false' as QUERYID, id, name, password, salt from user WHERE ( name = ? )
==> Parameters: zhang3(String)
<== Columns: QUERYID, id, name, password, salt
<== Row: false, 1, zhang3, a7d59dfc5332749cb801f86a24f5f590, e5ykFiNwShfCXvBRPr3wXg==
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b18608c]

同样,获取不到的时候:

null
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63fcf8ac] was not registered for synchronization because synchronization is not active
2019-01-17 16:58:43,509 - HikariPool-1 - Starting...
2019-01-17 16:58:43,605 - HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@801024502 wrapping com.mysql.cj.jdbc.ConnectionImpl@59fec4c6] will not be managed by Spring
==> Preparing: select 'false' as QUERYID, id, name, password, salt from user WHERE ( name = ? )
==> Parameters: li4(String)
<== Columns: QUERYID, id, name, password, salt
<== Row: false, 2, li4, 43e28304197b9216e45ab1ce8dac831b, jPz19y7arvYIGhuUjsb6sQ==
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63fcf8ac]

但最终会去数据库查找.

最后得出结论,当用户退出时,数据还会存在缓存,没清理干净.

比如这次我用户名输入li,而输出了上次的li4

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63a12f67] was not registered for synchronization because synchronization is not active
li4
JDBC Connection [HikariProxyConnection@1738454987 wrapping com.mysql.cj.jdbc.ConnectionImpl@59fec4c6] will not be managed by Spring
==> Preparing: select 'false' as QUERYID, id, name, password, salt from user WHERE ( name = ? )
==> Parameters: li(String)
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63a12f67]
li
login异常

具体参考这个

重登录:(数据库不存在的123)

2019-01-17 17:05:08,820 - Initializing Servlet 'dispatcherServlet'
2019-01-17 17:05:08,826 - Completed initialization in 6 ms
exception:userName->null
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@684cb0ac] was not registered for synchronization because synchronization is not active
2019-01-17 17:05:11,200 - HikariPool-1 - Starting...
2019-01-17 17:05:11,384 - HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@650094086 wrapping com.mysql.cj.jdbc.ConnectionImpl@2755b849] will not be managed by Spring
==> Preparing: select 'false' as QUERYID, id, name, password, salt from user WHERE ( name = ? )
==> Parameters: 123(String)
<== Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@684cb0ac]
exception:userName->123
login异常

不管怎样,能正常使用,可能也是登出用户时存在的问题.

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49fd93ed] was not registered for synchronization because synchronization is not active
exception:userName->14221
JDBC Connection [HikariProxyConnection@1195013282 wrapping com.mysql.cj.jdbc.ConnectionImpl@2755b849] will not be managed by Spring
==> Preparing: select 'false' as QUERYID, id, name, password, salt from user WHERE ( name = ? )
==> Parameters: zhang3(String)
<== Columns: QUERYID, id, name, password, salt
<== Row: false, 1, zhang3, a7d59dfc5332749cb801f86a24f5f590, e5ykFiNwShfCXvBRPr3wXg==
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49fd93ed]

14221是错误的用户名,

而之后的zhang3是存在的,但是不进入exception了.

是否应该自己写一个logout.

看到一个比较像的问题的博客

todo

在springboot中还有一个权限的扩展包: security

        <!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <!--security-config-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.1.5.RELEASE</version>
</dependency>

[shiro] - 加入rememberMe功能的更多相关文章

  1. Shiro的 rememberMe 功能使用指导(为什么rememberMe设置了没作用?)

    UsernamePasswordToken token = new UsernamePasswordToken(loginForm.getUsername(),loginForm.getPasswor ...

  2. Remember-Me功能

    Remember-Me功能 目录 1.1概述 1.2基于简单加密token的方法 1.3基于持久化token的方法 1.4Remember-Me相关接口和实现类 1.4.1TokenBasedReme ...

  3. Spring Security(12)——Remember-Me功能

    目录 1.1     概述 1.2     基于简单加密token的方法 1.3     基于持久化token的方法 1.4     Remember-Me相关接口和实现类 1.4.1    Toke ...

  4. Spring Security教程(七):RememberMe功能

    在之前的教程中一笔带过式的讲了下RememberMe记住密码的功能,那篇的Remember功能是最简易的配置,其功能和安全性都不强.这里就配置下security中RememberMe的各种方式. 一. ...

  5. springsecurity remember-me 功能

    本文基于spring-security-web-4.1.2.RELEASE. 要实现rememberMe,有两种方案. 1.基于简单加密token的方法 首先需要在配置文件中加入<remembe ...

  6. SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)

    首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cooki ...

  7. SpringBoot学习:整合shiro(rememberMe记住我功能)

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; ...

  8. SpringBoot学习:整合shiro(验证码功能和登录次数限制功能)

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)验证码 首先login.jsp里增加了获取验证码图片的标签: <body s ...

  9. shiro的三大功能

    1.提供的功能

随机推荐

  1. BUG笔记:Win8 IE10下input[type="password"]内字符显示被截取问题

    这个BUG发生的截图: 这是发生在Windows8 IE10下,type为password的input文本框内输入长串字符后,初次失去焦点的时候会发生的一个BUG. 发生BUG的原因是这个文本框上应用 ...

  2. Java-mybatis-一次执行多条SQL语句

    mysql数据库 1.修改数据库连接参数加上allowMultiQueries=true,如: hikariConfig.security.jdbcUrl=jdbc:mysql://xx.xx.xx: ...

  3. windows7触屏编程

    每当用户触摸触敏式 Windows 7 设备时,Windows 7 多点触控平台都会向您的应用程序发送手势消息 WM_GESTURE.这是现成的免费行为,如果您希望停止接收此类消息,则需要选择退出. ...

  4. [LeetCode] 310. Minimum Height Trees_Medium tag: BFS

    For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...

  5. 数据结构线性表的动态分配顺序存储结构算法c语言具体实现和算法时间复杂度分析

    #include<stdio.h>#include<stdlib.h>//线性表的动态分配顺序存储结构#define LIST_INIT_SIZE 100//线性表存储空间的初 ...

  6. file_get_post实现post请求

    function Post($url, $post = null){     $context = array();     if (is_array($post)) {       ksort($p ...

  7. 转载人家写的CURSOR

    转自:http://blog.csdn.net/rdarda/article/details/7881648 1.游标的作用及属性 游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操 ...

  8. 摘要JSR168 PORLET标准手册汉化整理

    本规范汉化资源搜集整理于网上并由我作了些修改和添加,主要为适应大陆的语辞.用语及其他未译之处. 由于本人于水平有限,如有错误,请各位高手指正:若有高见,希望不吝言辞,同为中国开源作项献. 特此严重感谢 ...

  9. 【upstream】Nginx配置upstream实现负载均衡

    如果Nginx没有仅仅只能代理一台服务器的话,那它也不可能像今天这么火,Nginx可以配置代理多台服务器,当一台服务器宕机之后,仍能保持系统可用.具体配置过程如下: 1. 在http节点下,添加ups ...

  10. 登录使用inode的校园网用到的url

    无需使用inode客户端,直接访问下面的url,然后输入账号密码即可. 第一次访问这个url的时候可能会提示下载inode客户端,再访问一次即可. url1:http://172.20.1.1/por ...