shiro笔记

很早之前就用shiro安全框架写登录。还没用到权限,单纯的登陆。
最近的项目不得不深入研究shiro
那时候使用都是即查即用。
现在不得不深入。于是遇到了一座大山,导致了所有的问题产生

SecurityUtils.getSubject().getPrincipal()

基础配置一个简洁的shiro框架需要

  • shiroRealm
  • shiroConfiguration

两个java文件,再加上maven依赖就可以基本的实现所有的权限登陆操作。

至于怎么配置可以网上查,大多数一样。

先到ShiroRealm的使用方法
使用ShiroRealm extends AuthorizingRealm
然后实现其抽象类

有两个方法

  • AuthenticationInfo
  • AuthorizationInfo

第一个为实现登录
第二个为实现权限

AuthenticationInfo

UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

此处token的为可以引用的参数
通过进入UsernamePasswordToken可以看到它的参数有

private String username;
private char[] password;
private boolean rememberMe = false;
private String host;
token.getUsername()

正常的操作是从token中getUserName。然后数据库查到userName对应的所有信息来参照密码

if (user != null) {
            Object principal = user.getUserName();
            Object credentials = user.getPassword();
            String realmName = getName();
            ByteSource credentialsSalt = ByteSource.Util.bytes(principal);

            return new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
        }

这里的 ByteSource.Util.bytes(principal);
是我自己实现的md5加密方法

最后返回
SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName)
得到对应密码

AuthorizationInfo

它实现的只是查找权限和角色
我们先看下实现代码

 User user = (User) SecurityUtils.getSubject().getPrincipal();
        String userName = user.getUsername();

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        // 获取用户角色集
        List<Role> roleList = this.roleService.findUserRole(userName);
        Set<String> roleSet = roleList.stream().map(Role::getRoleName).collect(Collectors.toSet());
        simpleAuthorizationInfo.setRoles(roleSet);

        // 获取用户权限集
        List<Menu> permissionList = this.menuService.findUserPermissions(userName);
        Set<String> permissionSet = permissionList.stream().map(Menu::getPerms).collect(Collectors.toSet());
        simpleAuthorizationInfo.setStringPermissions(permissionSet);
        return simpleAuthorizationInfo;
    

上面用了jdk8的特性stream。语法糖是个好东西
通过实例化SimpleAuthorizationInfo
分别存入

  • setRoles
  • setStringPermissions

最后 return simpleAuthorizationInfo;
获得对应的权限和角色

这里可以看到我遇到的山了
SecurityUtils.getSubject().getPrincipal()

这里有一个问题
AuthorizationInfo
它到底什么时候会被引用到?
按照我的理解,它也只有需要操作到权限时候才会调用这个函数。

有几种方式

  • 通过config的配置
    我用的是SpringBoot,不需要xml配置,直接新建一个java声明。其中config中需要实现不少配置,如下的过滤器
    @Bean(name = “shiroFilter”)
    public ShiroFilterFactoryBean shiroFilterFactoryBean(
    org.apache.shiro.mgt.SecurityManager securityManager)
    我后面会提到
  • 通过前端页面html的javascript调用
  • @RequiresPermissions(value ="")
    在controller中可以在@RequestMapping下判定权限

我们看一下这一句

 User user = (User) SecurityUtils.getSubject().getPrincipal();

这里的getPrincipal();
它得到的是一个Object类型。从源码来看,它的实现是用迭代器遍历Object的每一个属性的。
重点就是这里,他是哪里来的?
那时候调用了这个函数,它给我报了个错

java.lang.String cannot be cast to com.b2b.java.po.UserPo

通过logger日志输出,得到getPrincipal的值是String。单纯的String类型。
通过我的查找。真正声明principal的函数是

AuthenticationInfo。的return 语句

  return new SimpleAuthenticationInfo(user, credentials, credentialsSalt, getName());
//这里是我修改好了的

因为没有认真研究源码的参数所以误传值进去

 Object principal = user.getUserName();

真正的应该是

 Object principal = user;

我们看看它的源码

* @param principal         the 'primary' principal associated with the specified realm.
     * @param hashedCredentials the hashed credentials that verify the given principal.
     * @param credentialsSalt   the salt used when hashing the given hashedCredentials
     * @param realmName         the realm from where the principal and credentials were acquired.
     
 public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
        this.principals = new SimplePrincipalCollection(principal, realmName);
        this.credentials = hashedCredentials;
        this.credentialsSalt = credentialsSalt;
    }

上面的注释已经很清楚了
所以应该传入Object类型。

小结

以后报错的时候必须看源码

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值