JavaWeb项目:Shiro实现简单的权限控制(整合SSM)
该demo整合Shiro的相关配置参考开涛的博客
数据库表格相关设计
 
表格设计得比较简单,导航栏直接由角色表auth_role的角色描述vRoleDesc(父结点)和角色相关权限中的权限描述(标记为导航结点)vPermissionDesc(展开子项)组成。 
Shiro相关设置
密码输入错误次数限制
//密码重试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:用于登录后获取用户导航栏,并将其存入session范围
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实现(用户密码不匹配情况下执行)
@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;
    }
    //...
}登录表单代码:注意提交action=”“,以及输入控件name值须与form表单过滤器中的设置对应
<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>最后通过Spring注解,控制访问
@RequiresPermissions("user:list")
    @RequestMapping("/list")
    public ModelAndView showUserList(){
        //
    }完整shiro配置如下:
<?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>其他如dao、service、controller组件实现省略
完整代码见:https://github.com/weixupeng/auth-control_SSM
JavaWeb项目:Shiro实现简单的权限控制(整合SSM)的更多相关文章
- JAVAEE——BOS物流项目11:在realm中授权、shiro的方法注解权限控制、shiro的标签权限控制、总结shiro的权限控制方式、权限管理
		1 学习计划 1.在realm中进行授权 2.使用shiro的方法注解方式权限控制 n 在spring文件中配置开启shiro注解支持 n 在Action方法上使用注解 3.★使用shiro的标签进行 ... 
- Spring项目集成ShiroFilter简单实现权限管理
		Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ... 
- elasticsearch使用jetty进行简单的权限控制
		默认elasticsearch是使用netty作为http的容器,由于netty并没有权限模块,所以默认es没有任何的权限控制,直接通过http就可以进行任何操作,除非把http禁用.但如果你使用el ... 
- Shiro的认证和权限控制
		权限控制的方式 从类别上分,有两大类: - 认证:你是谁?–识别用户身份. - 授权:你能做什么?–限制用户使用的功能. 权限的控制级别 从控制级别(模型)上分: - URL级别-粗粒度 - 方法级别 ... 
- shiro框架的四中权限控制方式
		https://www.cnblogs.com/cocosili/p/7103025.html 一.在自定义的realm中进行权限控制 在applicationContext.xml文件中添加 /a ... 
- **CodeIgniter通过hook的方式实现简单的权限控制
		根据自己的实际情况,需要两个文件,一个是权限控制类,Acl,另外一个是权限配置的文件acl.php放在了config这个目录下. Acl这个类放在了application/hook/acl.php.通 ... 
- springboot+mybatis+shiro——登录认证和权限控制
		转载:https://z77z.oschina.io/ 一.引入依赖 shiro-all包含shiro所有的包.shiro-core是核心包.shiro-web是与web整合.shiro-spring ... 
- shiro框架学习-7- Shiro权限控制注解和编程方式
		讲解权限角色控制 @RequiresRoles, @RequiresPermissions等注解的使用和编程式控制 配置文件的方式 使用ShiroConfig 注解方式 @RequiresRoles( ... 
- [PHP] 最简单的权限控制设计
		假设url部分我们只有action和method , 某个控制器下的某个方法 , 比如:log/loginlog 查看日志下的登陆日志, action就是log , method就是loginlo ... 
随机推荐
- python中英文翻译模块
			从一种语言到另一种语言的文本翻译在各种网站中越来越普遍. 帮助我们执行此操作的python包称为translate. 可以通过以下方式安装此软件包. 它提供主要语言的翻译. 官网:https://py ... 
- List&LinQ
			DataTable会将整个数据表接收过来,可真正使用的数据未必是整个数据表所有的数据. 使用List可以接收需要使用的数据 public class Data_Model { public strin ... 
- Idea创建多模块依赖Maven项目
			idea 创建多模块依赖Maven项目 本来网上的教程还算多,但是本着自己有的才是自己的原则,还是自己写一份的好,虽然可能自己也不会真的用得着. 1. 创建一个新maven项目 2. 3. 输入g ... 
- GET和POST请求的区别和使用场景
			本质上的区别: GET请求.处理.响应过程中只是产生一个TCP数据包,而POST请求会产生两个TCP数据包. 更具体地说,GET请求过程中头和请求正文数据一起到服务器端, 而POST请求过程中, ... 
- 工作笔记--js-点赞按钮和踩踩按钮互斥??怎么写?
			效果图: html: css: .an{ margin-top:0px; position: relative; .popzframe,.popcframe{ display: none; word- ... 
- word和画图
			文档和画图收费文档:edu.51cto.com/course/course_id-4992.htmledu.51cto.com/course/course_id-4991.html 
- Devexpress MVC GridView / CardView (持续更新)
			//获取gridview里面的combo box 显示的文本 //获取某个column在gridview的 index RightGridView.GetColumnByField("Fun ... 
- (76)深入浅出Mqtt协议
			物联网(Internet of Things,IoT)时代机器之间(Machine-to-Machine,M2M)的大规模沟通需要发布/订阅(Publish/Subscribe)模式,轻量级.易扩展的 ... 
- Mysql 获取成绩排序后的名次
			其实就是输出mysql的排序后的行号 RT:获取单个用户的成绩在所有用户成绩中的排名 可以分两步: 1.查出所有用户和他们的成绩排名 ) as rowNo from t_user, () ) ... 
- JS深度判断两个数组对象字段相同
			/** * 判断此对象是否是Object类型 * @param {Object} obj */ function isObject(obj){ return Object.prototype.toSt ... 
