多了不说了,进入正题,shiro是个权限框架提供权限管理等功能,网上的教程一般都是互相抄,比如<shiro:principal property="xxx"/>这个标签,网上教程告诉你可以用来获取登录用户的任何属性,但现实中如果你这么写,并且按照开涛教程上写的登陆逻辑,肯定百分百报错,这是为什么呢?因为网上教程的登录部分一般这么写:

这是重写authorizingrealm的dogetAuthenticationinfo方法:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
String username=(String) token.getPrincipal();
User user=userService.getUserByUsername(username);
if(user==null){
throw new UnknownAccountException();
}
if(user.getUserState()==4){
throw new LockedAccountException();
}
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),
this.getName()
);
 
return info;


网上很多教程都是这么教给大家的, 然后在controller里用:
UsernameAndPasswordToken token=new UsernameAndPasswordToken(username,password);
subject.login(token);
....
这一系列逻辑来进行登陆,登陆成功后在页面通过<shiro:principal property="username"/>来获取登录用户属性,然后你这么做了就报错了。
为什么?来看源码,源码一是一手鞋,官方文档是二手鞋,网上教程是三手鞋,鞋都穿三手了,兴许会有脚气。。。

    public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
        this.principals = new SimplePrincipalCollection(principal, realmName);
        this.credentials = hashedCredentials;
        this.credentialsSalt = credentialsSalt;

}
上面是SimpleAuthenticationInfo源码的一个构造方法,这里第一个参数就是你刚才传入的用户名,第二个参数就是你传入的密码,但是方法定义中这两个参数都是Object类型,尤其是第一个principal参数,它的意义远远不止用户名那么简单,它是用户的所有认证信息集合,登陆成功后,<shiro:principal/>标签一旦有property属性,PrincipalTag类也就是标签的支持类,会从Subject的principalcollection里将principal取出,取出的就是你传入的第一个参数,如果你传了个string类型的用户名,那么你只能获取用户名。
仔细看那个this.principals=new SimplePrincipalCollection,这一行,这一行构造了一个新的对象并将引用给了principals,而principals就是principalcollection。
再来看Principal那个标签<shiro:principal property=""/>那个,打开PrincipalTag类,看到onDoStartTag方法:

    public int onDoStartTag() throws JspException {
        String strValue = null;
 
        if (getSubject() != null) {
 
            // Get the principal to print out
            Object principal;
 
            if (type == null) {
                principal = getSubject().getPrincipal();
            } else {
                principal = getPrincipalFromClassName();
            }
 
            // Get the string value of the principal
            if (principal != null) {
                if (property == null) {
                    strValue = principal.toString();
                } else {
                    strValue = getPrincipalProperty(principal, property);
                }
            }
 
        }
 
        // Print out the principal value if not null
        if (strValue != null) {
            try {
                pageContext.getOut().write(strValue);
            } catch (IOException e) {
                throw new JspTagException("Error writing [" + strValue + "] to JSP.", e);
            }
        }
 
        return SKIP_BODY;


看到那个Object principal这个方法变量了么?如果标签里没有type属性,那么就直接调用getPrincipal方法,再打开这个方法,看到subject里是这么写的:

    public Object getPrincipal() {
        return getPrimaryPrincipal(getPrincipals());


getPrincipals是获取principalcollection,getprimaryprincipal就是获取这个principalcollection的第一个元素,用的是迭代器的方式获取。具体的我不列出来了,请参见SimplePrincipalcollection的源代码。
第一个元素你最初放的是用户名,所以你可以取得这个用户名。 如果type不为空,就会去principalcollection中找和这个type类型一致的一个对象,看源码:

    private Object getPrincipalFromClassName() {
        Object principal = null;
 
        try {
            Class cls = Class.forName(type);
            principal = getSubject().getPrincipals().oneByType(cls);
        } catch (ClassNotFoundException e) {
            if (log.isErrorEnabled()) {
                log.error("Unable to find class for name [" + type + "]");
            }
        }
        return principal;


那个oneByType方法就是在principalcollection中找和type属性一致的那个类的对象,将其作为principal,如果<shiro:property/>标签有了property属性,然后用java内省机制获取bean的属性,参见getPrincipalProperty方法,因为方法体太长我就不列出了。 
所以你现在知道该怎么做了吧?
在你的realm里这么写:

List<Object> principals=new ArrayList<Object>();
principals.add(user.getUsername());
principals.add(user);
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
principals,
user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),
this.getName()

);
构建一个list,第一个元素是用户名,第二个元素是user对象。第一个元素用来登陆,第二个元素用来获取登陆后user对象的属性。
他们到底怎么判断登陆的呢?
先参见HashedCredentialsMatcher类的这个方法,这是用来判断是否可以登录成功的方法:  
  public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

        Object tokenHashedCredentials = hashProvidedCredentials(token, info);
        Object accountCredentials = getCredentials(info);
        return equals(tokenHashedCredentials, accountCredentials);


其中第一个参数token就是controller里封装的token,第二个参数info就是你刚才的simpleauthenticationinfo,因为源码层次比较深所以简单点说,这个方法就是再判断两个密码是否相等,因为两个用户名肯定是相等的info的用户名是token传过来的,所以只对比密码就可以了。 
就写这么多吧,希望大家看了能有启发。

   不是我写的,是我在开发中遇到问题,特此复制别人解决办法的博客  附上 大牛的链接  http://blog.csdn.net/ccdust/article/details/52300287

关于Apache Shiro权限框架的一些使用误区的解释的更多相关文章

  1. Apache Shiro权限框架在SpringMVC+Hibernate中的应用

    在做网站开发中,用户权限必须要考虑的,权限这个东西很重要,它规定了用户在使用中能进行哪 些操作,和不能进行哪些操作:我们完全可以使用过滤器来进行权限的操作,但是有了权限框架之后,使用起来会非常的方便, ...

  2. Apache Shiro 权限框架

    分享一个视屏教程集合 http://www.tudou.com/home/konghao/item 1.Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码 ...

  3. Shiro权限框架简介

    http://blog.csdn.net/xiaoxian8023/article/details/17892041   Shiro权限框架简介 2014-01-05 23:51 3111人阅读 评论 ...

  4. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  5. 在前后端分离的SpringBoot项目中集成Shiro权限框架

    参考[1].在前后端分离的SpringBoot项目中集成Shiro权限框架 参考[2]. Springboot + Vue + shiro 实现前后端分离.权限控制   以及跨域的问题也有涉及

  6. SpringBoot整合Apache Shiro权限验证框架

    比较常见的权限框架有两种,一种是Spring Security,另一种是Apache Shiro,两种框架各有优劣,个人感觉Shiro更容易使用,更加灵活,也更符合RABC规则,而且是java官方更推 ...

  7. Apache Shiro(安全框架)

    当前常用流行的安全框架主要有两种:一个是Apache Shiro:另一个是Springsource. 现在介绍一下apache shiro: 既然是安全框架,解决的肯定是权限的 控制.所谓权限是指:用 ...

  8. Shiro 权限框架使用总结

    我们首先了解下什么是shiro ,Shiro 是 JAVA 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性方面拥有巨 ...

  9. shiro权限框架

    权限的组成部分:用户 资源 角色 权限 数据库关系表设计是根据自己项目需求设计的 account表role表(id,rolename)account_role(id,aid,rid)permissio ...

随机推荐

  1. Alternating Least Squares(ASL) for Implicit Feedback Datasets的数学推导以及用Python实现

    近期在看CF的相关论文,<Collaborative Filtering for Implicit Feedback Datasets>思想非常好,非常easy理解.可是从目标函数 是怎样 ...

  2. Excle数组用法

    现在有如下需求:需要将行与列进行乘积,并将结果录入到对应单元格 [需求展示] 面对上面这样的表格,你会怎么处理呢?一个个乘积后录入吗?还是使用公式一行行操作? [解决办法] 这种问题,使用数组是最好解 ...

  3. python机器学习-逻辑回归

    1.逻辑函数 假设数据集有n个独立的特征,x1到xn为样本的n个特征.常规的回归算法的目标是拟合出一个多项式函数,使得预测值与真实值的误差最小: 而我们希望这样的f(x)能够具有很好的逻辑判断性质,最 ...

  4. HttpClient POST 的 UTF-8 编码问题

    http://www.360doc.com/content/09/0915/15/61497_6003890.shtml不 过在实际使用中, 还是发现按照最基本的方式调用 HttpClient 时, ...

  5. 完美运动框架(js)

    一.前言 学习js运动时,由于在实现多种不同运动效果过程中很多代码是重复的,故将其封装达到代码重用. 二.代码封装重用 function startMove(obj, json, fnEnd){ cl ...

  6. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 索引的类型  按查找方式分,两种,分块索引 vs编号索引1 1.2. 按索引与数据的查找顺序可分为 正 ...

  7. Timer和ScheduledExecutorService区别

    Timer特点:   1.一个Timer只占用一个线程 timer有多个timerTask的情况,如果一个timerTask有执行时间过长,其它的timerTask就会被耽误 2.如果TimerTas ...

  8. 如何理解HTTP协议的“无连接,无状态”特点

    是一个属于应用层的面向对象的协议,HTTP 协议一共有五大特点:1.支持客户/服务器模式;2.简单快速;3.灵活;4.无连接;5.无状态. 无连接 无连接的含义是限制每次连接只处理一个请求.服务器处理 ...

  9. AF_UNIX和AF_INET域的socket在epoll中的差异

    1.AF_UNIX & SOCK_STREAM 1.1 accept_socket BLOCK EPOLLIN|EPOLLET 1.2 accept_socket NON-BLOCK EPOL ...

  10. Nginx编译安装第三方模块http_substitutions_filter_module

    Nginx编译安装第三方模块http_substitutions_filter_module 分类:服务器技术  作者:rming  时间:-- . >>ngx_http_substitu ...