权限框架shiro的的一个问题

同样是两次post的表单提交

我在自定义Realm中的doGetAuthenticationInfo方法里执行String userName = (String) authenticationToken.getPrincipal();有时能取到值,有时取不到,比较奇怪.

于是我开始找authenticationToken.getPrincipal()的实现,一层一层往上找后发现,就是request.getParameter("username")

  • 图1
    clipboard.png

  • 图2
    clipboard.png

  • 图3
    clipboard.png

我遇到的情况如下

  • 正常情况下,前端提交username和password,是能从shiro里获取到username的

clipboard.png

  • 但是,有少数几次,会遇到下图这样的问题

    • 明明前端提交了username,但是shiro里却获取不到,而且没有改任何代码和参数,这个错误也只是极少数情况出现,很难重现,为了截取到下面这张图,我硬是登陆退出了7 80次……

clipboard.png

下面是我shiro的配置文件

<?xml version="1.1" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
       default-lazy-init="true">

    <description>Shiro安全配置</description>

    <!-- 读取配置文件 -->
    <context:property-placeholder ignore-unresolvable="true"
                                  location="classpath*:/config/privsys.properties"/>

    <!-- 安全管理器  Shiro的主要业务层对象基于web的应用程序 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="customAuthorizingRealm"/>
        <!-- 注入session管理器 -->
        <property name="sessionManager" ref="sessionManager"/>
    </bean>

    <!-- 会话管理 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- session的失效时常,单位是毫秒 -->
        <property name="globalSessionTimeout" value="600000"/>
        <!-- 删除失效的session -->
        <property name="deleteInvalidSessions" value="true"/>
    </bean>

    <bean id="customAuthorizingRealm" class="com.hongyun.privsys.shiro.CustomAuthorizingRealm">
       
    </bean>


    <!-- 注销的时候 登出 跳转到login页面-->
    <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
        <property name="redirectUrl" value="/login.jsp"/>
    </bean>

    <!-- Shiro Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!-- loginUrl认证提交地址,如果认证没有通过,shiro框架就会自动请求这个地址 -->
        <property name="loginUrl" value="${privsys.shiro.loginUrl}"/>
        <!-- 如果没有权限,shiro框架就会自动请求这个地址 -->
        <property name="unauthorizedUrl" value="${privsys.shiro.unauthorizedUrl}"/>

        <!--认证成功自动跳转,不配置自动到上一个请求路径 一般不配置-->
        <property name="successUrl" value="${privsys.shiro.successUrl}"/>

        <!-- **去掉了自定义过滤器** -->
        <property name="filters">
            <map>
      <!--          <entry key="authc" value-ref="formAuthenticationCaptchaFilter"/>-->
                <entry key="logout" value-ref="logoutFilter"/>
            </map>
        </property>

        <property name="filterChainDefinitions">
            <value>
                <!--从上往下执行 优先执行的放前面 anon 允许匿名访问(资源文件)  authc允许登录验证访问(所有页面) perms运行权限验证访问 logout自动退出(url可以不存在)user 记住我或认证通过可以访问的地址 /index.html=user  authcBasic不关闭浏览器不清除session-->
                <!--
                    从上往下执行,上面的先于下面的执行,所以将覆盖面小的要放在上边
                    anon 可以匿名访问
                    logout 由shiro的LogoutFilter拦截住,然后清除session信息,退出登陆的url可以不存在
                -->
                /test.do = anon
                /logout.do=logout
                /login.jsp=anon
                /testlogin/login.jsp=anon
                /login.html = anon
                /login.do=authc
                /captcha-image.do = anon
                /favicon.ico = anon
                /purview/** = anon
                /resources/** = anon
                /apps/** = anon
                /assets/** = anon
                /error/** = anon
                /home/** = authc
                /json/** = anon
                /!loginAndPortal/** = anon
                /**=authc
            </value>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">/privsys/error/403</prop>
            </props>
        </property>
    </bean>


    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor"
          class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- AOP式方法级权限检查  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>

    <!-- shiro权限注解支持开启  -->
    <aop:config proxy-target-class="true"></aop:config>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
</beans>

在web.xml中shiroFilter前只有一个Spring的encodingFilter

我把shiro缓存和cookie的记住我功能全部都去掉了,但是还是会出现这样的问题,不知道该如何解决了,希望有知道的朋友能给个思路什么的,谢谢了

阅读 9k
4 个回答

1、首先给你个demo。

/**
 * Created by projack
 * 权限认证服务
 */
public class CmsShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获取当前登录的用户名
        String name = (String) super.getAvailablePrincipal(principals);

        List<String> roles = new ArrayList<String>();
        List<String> permissions = new ArrayList<String>();
        User user = userService.findByName(name);
        if(user != null){
            for(Role role : user.getRoles()){
                roles.add(role.getName());
            }
            Set<Permission> pmssSet = userService.getPermissionsByUserId(user.getUserId());
            for(Permission pms : pmssSet){
                if(!StringUtils.isEmpty(pms.getPermission())){
                    permissions.add(pms.getPermission());
                }
            }
        }else{
            throw new AuthorizationException();
        }
        //给当前用户设置角色
        info.addRoles(roles);
        //给当前用户设置权限
        info.addStringPermissions(permissions);
        return info;
    }

    /**
     * 认证信息.(身份验证),登录时调用
     * @param token
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户的输入的账号.
        String username = (String)token.getPrincipal();
        //通过username从数据库中查找 User对象,如果找到,没找到.
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        User user = userService.findByName(username);
        if(user == null){
            return null;
        }
       /*
        * 获取权限信息:这里没有进行实现,
        * 请自行根据User,Role,Permission进行实现;
        * 获取之后可以在前端for循环显示所有链接;
        */
        //user.setPermissions(userService.findPermissions(user));

        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getName(),user.getPassWord(),user.getNickName());
        return authenticationInfo;
    }
}

2、Shiro根本就不用你的HttpSevletRequest和Response对象,Shiro自身维护了自己的Session,在Shrio的包下面。

楼主问题你已经定位到这里了。还在想着有机率会出现Bug?看你定位代码的程度已经非常深入了,这里就是简单的在request中拿个值。拿不到这显示是在Request中没有该值。这与shiro没有任何关系。

你看这张图,你定位到这里来了,为什么没有查看一下request中的参数呢?就是那个@10319对象。

你截图里,能拿到的url是127.0.0.1,不能拿到的url是localhost,不知是不是和这个有关

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏