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>

最新文章

  1. ajax下载多文件,并且打包 C#中 ,文件批下载zip
  2. IOS第八天(6:UITableViewController新浪微博, 模型和 控件位置封装一起statusFrame)
  3. Delphi的哈希表(一)
  4. UVA 10817 十一 Headmaster&#39;s Headache
  5. eclipse 连接 mysql
  6. UINavigationController &#160;和 UITabBarController
  7. CentOS 6下安装nodejs 0.9.0(转)
  8. 一天搞定HTML----标签类型与类型转换05
  9. css 2D转换 transform-rotate 画插图
  10. Python处理图片缩略图
  11. 手写简单的jq雪花飘落
  12. 使用Java代码发送邮件
  13. shell脚本三——正则表达式
  14. Django 中的JsonResponse 和 json区别
  15. C++学习笔记40:进程应用
  16. 基础的linux学习
  17. Hello World! 我的程序员入坑之旅!
  18. Debug文件夹是什么
  19. sqlserver 2008备份与还原
  20. SQL Server快速部署作业到多台服务器

热门文章

  1. [py]处理文件的3个方法
  2. Filter与Servlet的区别与联系
  3. MongoDB和pymongo自用手册
  4. Xcode 快捷键及代码格式化
  5. web前端面试小结(1)
  6. 删除排序数组中的重复数字 II
  7. css3 3d翻转效果
  8. ping和telnet的区别
  9. OAuth : open Authorization 开发授权
  10. java多线程----拒绝策略