JavaWeb项目:Shiro实现简单的权限控制(整合SSM)

简介: JavaWeb项目:Shiro实现简单的权限控制(整合SSM) 数据库表格相关设计 表格设计得比较简单,导航栏直接由角色表auth_role的角色描述vRoleDesc(父结点)和角色相关权限中的权限描述(标记为导航结点)vPermissionDesc(展开子项)组成。

的JavaWeb项目:四郎实现简单的权限控制(整合SSM)

数据库表格相关设计

这里写图片描述
表格设计得比较简单,导航栏由角色表auth_role角色描述vRoleDesc(父结点)和角色相关权限中的权限描述(标记为导航结点)vPermissionDesc(展开子项)组成。

四郎相关设置

密码输入错误次数限制

//密码重试5次次数限制 
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher{
    private Cache<String,AtomicInteger> passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager){
        passwordRetryCache=cacheManager.getCache("passwordRetryCache");
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username=(String)token.getPrincipal();
        AtomicInteger retryCount=passwordRetryCache.get(username);
        if(retryCount==null){
            retryCount=new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet()>5){
            throw new ExcessiveAttemptsException();
        }
        boolean matches= super.doCredentialsMatch(token, info);//匹配密码
        if(matches){
            passwordRetryCache.remove(username);
        }
        return matches;
    }
}

相关配置:

<!-- 凭证(密码)匹配器 -->
    <bean id="credentialsMatcher" class="com.test.shiro.credentials.RetryLimitHashedCredentialsMatcher">
        <constructor-arg ref="cacheManager"/>
        <property name="hashAlgorithmName" value="md5"/><!--md5加密-->
        <property name="hashIterations" value="2"/><!--加密迭代两次-->
        <property name="storedCredentialsHexEncoded" value="true"/><!--为true时使用Hex编码(默认);false时使用Base64编码-->
    </bean>

使用缓存实现为的Ehcache,相关配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="shiroCache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
   xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <diskStore path="java.io.tmpdir"/> 
    <cache name="passwordRetryCache"
        maxEntriesLocalHeap="2000"
        eternal="false"<!--非永久有效-->
        timeToIdleSeconds="3600"<!-- 对象空闲时间,即60min后失效-->
        timeToLiveSeconds="0"
        overflowToDisk="false"
        statistics="true">
    </cache>
    <!--...-->
</ehcache>

扩展AuthorizingRealm:用于从数据库抓取密码等相关验证信息和相关权限信息

public class UserRealm extends AuthorizingRealm{

    @Autowired
    private UserService userService;

    //获取相关授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName=(String)principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findPermissionsByUserName(userName));//获取角色信息
        authorizationInfo.setStringPermissions(userService.findPermissionsByUserName(userName));//获取权限信息

        return authorizationInfo;
    }

    //获取身份验证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName=(String)token.getPrincipal();
        User user=userService.getUserByUserName(userName);//获取身份信息(密码和密码盐)
        if(user==null){
            throw new UnknownAccountException();
        }
        SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(
                user.getUserName(),
                user.getPassword(),
                ByteSource.Util.bytes(user.getUserName()+user.getPasswordSalt()),
                getName());
        return authenticationInfo;
    }

}

登录相关

扩展FormAuthenticationFilter:用于登录后获取用户导航栏,并将其存入会话范围

public class WithNavibarFormAuthenticationFilter extends FormAuthenticationFilter {

    @Autowired
    private UserService userService;

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
            ServletResponse response) throws Exception {
        HttpServletRequest httpReq=(HttpServletRequest)request;

        String userName=(String)SecurityUtils.getSubject().getPrincipal();
        List navigationBar=userService.getNavigationBar(userName);
        httpReq.getSession().setAttribute("navibar", navigationBar);
        return super.onLoginSuccess(token, subject, request, response);
    }

}

登录控制器实现(用户密码不匹配情况下执行)

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //...

    @RequestMapping("/login")
    public ModelAndView login(HttpServletRequest req){
        String error=null;
        String exceptionClassName = (String)req.getAttribute("shiroLoginFailure");
        if(UnknownAccountException.class.getName().equals(exceptionClassName)) {
            error = "用户名/密码错误";
        } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
            error = "用户名/密码错误";
        } else if(exceptionClassName != null) {
            error = "其他错误:" + exceptionClassName;
        }
        ModelAndView mav=new ModelAndView("login");
        mav.addObject("error", error);
        return mav;
    }
    //...
}

登录表单代码:注意提交行动=”“,以及输入控件名称值须与形式表单过滤器中的设置对应

<form class="form-signin" method="post" action="">
        <h3 class="form-signin-heading">请登录</h3>
        <label for="inputEmail" class="sr-only">用户名</label>
        <input type="text" id="inputEmail" class="form-control" placeholder="用户名" name="username" required autofocus>
        <label for="inputPassword" class="sr-only">密码</label>
        <input type="password" id="inputPassword" class="form-control" placeholder="密码" name="password" required>
        <div class="checkbox">
          <label>
            <input type="checkbox" name="rememberMe"> 记住我
          </label>
        </div>
        <p class="bg-warning">${error}</p>
        <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
      </form>

最后通过春注解,控制访问

@RequiresPermissions("user:list")
    @RequestMapping("/list")
    public ModelAndView showUserList(){
        //
    }

完整四郎配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!-- 缓存管理器 使用Ehcache实现 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:config/ehcache.xml"/>
    </bean>
    <!-- 凭证(密码)匹配器 -->
    <bean id="credentialsMatcher" class="com.test.shiro.credentials.RetryLimitHashedCredentialsMatcher">
        <constructor-arg ref="cacheManager"/>
        <property name="hashAlgorithmName" value="md5"/>
        <property name="hashIterations" value="2"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>  
    <!-- Realm实现 -->
    <bean id="userRealm" class="com.test.shiro.realm.UserRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <property name="cachingEnabled" value="true"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>
    <!-- 会话ID生成器 -->
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

    <!-- 会话Cookie模板 -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="sid"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="180000"/>
    </bean>

    <!-- 会话DAO -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
        <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
    </bean>

    <!-- 会话验证调度器 -->
    <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
        <property name="sessionValidationInterval" value="1800000"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>

    <!-- 会话管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="globalSessionTimeout" value="1800000"/>
        <property name="deleteInvalidSessions" value="true"/>
        <property name="sessionValidationSchedulerEnabled" value="true"/>
        <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
        <property name="sessionDAO" ref="sessionDAO"/>
        <property name="sessionIdCookieEnabled" value="true"/>
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
    </bean>

    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <property name="sessionManager" ref="sessionManager"/>
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

    <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    </bean>
    <!-- 基于Form表单的身份验证过滤器 -->
    <bean id="formAuthenticationFilter" class="com.test.shiro.filter.WithNavibarFormAuthenticationFilter">
        <property name="usernameParam" value="username"/>
        <property name="passwordParam" value="password"/>
        <property name="rememberMeParam" value="rememberMe"/>
        <property name="loginUrl" value="/user/login"/><!--注意value值为登录url-->
    </bean>
    <!-- Shiro的Web过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/user/login"/>
        <property name="filters">
            <util:map>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /=authc
                /index=authc
                /user/login=authc<!-- 使用表单filter authc -->
                /logout=logout
                /static/**=anon<!-- 不拦截静态资源文件 -->
                /**=user
            </value>
        </property>
    </bean>

    <!-- Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

</beans>

地址原文http://www.bieryun.com/1930.html

相关文章
|
1月前
|
Java 应用服务中间件 开发工具
苍穹外卖》电商实战项目(java)知识点整理(上)
苍穹外卖》电商实战项目(java)知识点整理(上)
174 3
|
2月前
|
Java Maven
java修改当前项目的maven仓库地址为国内
修改当前项目的maven仓库地址为国内
|
1月前
|
SQL Java 应用服务中间件
Java项目防止SQL注入的四种方案
Java项目防止SQL注入的四种方案
37 0
|
25天前
|
人工智能 监控 算法
java智慧城管源码 AI视频智能分析 可直接上项目
Java智慧城管源码实现AI视频智能分析,适用于直接部署项目。系统运用互联网、大数据、云计算和AI提升城市管理水平,采用“一级监督、二级指挥、四级联动”模式。功能涵盖AI智能检测(如占道广告、垃圾处理等)、执法办案、视频分析、统计分析及队伍管理等多个模块,利用深度学习优化城市管理自动化和智能化,提供决策支持。
200 4
java智慧城管源码 AI视频智能分析 可直接上项目
|
2月前
|
监控 IDE Java
Java项目调试实战:如何高效调试Spring Boot项目中的GET请求,并通过equalsIgnoreCase()解决大小写不一致问题
Java项目调试实战:如何高效调试Spring Boot项目中的GET请求,并通过equalsIgnoreCase()解决大小写不一致问题
40 0
|
10天前
|
监控 数据可视化 安全
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
环境实时数据、动态监测报警,实时监控施工环境状态,有针对性地预防施工过程中的环境污染问题,打造文明生态施工,创造绿色的生态环境。
8 0
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
|
11天前
|
SQL Java Go
java项目超市购物管理系统
java项目超市购物管理系统
|
11天前
|
Java
java项目日历表
java项目日历表
|
23天前
|
Java Maven
运行maven项目出现Error:java: JDK isn‘t specified for module ‘XXX‘
运行maven项目出现Error:java: JDK isn‘t specified for module ‘XXX‘
11 0
|
23天前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
26 0