该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)的更多相关文章

  1. JAVAEE——BOS物流项目11:在realm中授权、shiro的方法注解权限控制、shiro的标签权限控制、总结shiro的权限控制方式、权限管理

    1 学习计划 1.在realm中进行授权 2.使用shiro的方法注解方式权限控制 n 在spring文件中配置开启shiro注解支持 n 在Action方法上使用注解 3.★使用shiro的标签进行 ...

  2. Spring项目集成ShiroFilter简单实现权限管理

    Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ...

  3. elasticsearch使用jetty进行简单的权限控制

    默认elasticsearch是使用netty作为http的容器,由于netty并没有权限模块,所以默认es没有任何的权限控制,直接通过http就可以进行任何操作,除非把http禁用.但如果你使用el ...

  4. Shiro的认证和权限控制

    权限控制的方式 从类别上分,有两大类: - 认证:你是谁?–识别用户身份. - 授权:你能做什么?–限制用户使用的功能. 权限的控制级别 从控制级别(模型)上分: - URL级别-粗粒度 - 方法级别 ...

  5. shiro框架的四中权限控制方式

    https://www.cnblogs.com/cocosili/p/7103025.html 一.在自定义的realm中进行权限控制 在applicationContext.xml文件中添加  /a ...

  6. **CodeIgniter通过hook的方式实现简单的权限控制

    根据自己的实际情况,需要两个文件,一个是权限控制类,Acl,另外一个是权限配置的文件acl.php放在了config这个目录下. Acl这个类放在了application/hook/acl.php.通 ...

  7. springboot+mybatis+shiro——登录认证和权限控制

    转载:https://z77z.oschina.io/ 一.引入依赖 shiro-all包含shiro所有的包.shiro-core是核心包.shiro-web是与web整合.shiro-spring ...

  8. shiro框架学习-7- Shiro权限控制注解和编程方式

    讲解权限角色控制 @RequiresRoles, @RequiresPermissions等注解的使用和编程式控制 配置文件的方式 使用ShiroConfig 注解方式 @RequiresRoles( ...

  9. [PHP] 最简单的权限控制设计

    假设url部分我们只有action和method , 某个控制器下的某个方法 , 比如:log/loginlog   查看日志下的登陆日志, action就是log , method就是loginlo ...

随机推荐

  1. 常用命令之------ln

    当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在某个固定的目录,放上该文件,然后在 其它的目录下用ln命令链接(link)它就可以,不必重复的 ...

  2. create-react-app踩坑记

    前言 哇,不的不说这个react 这个脚手架create-react-app脚确实有很多问题,哈哈,下面来看看吧有哪些坑: 引用sass或者less 记得16年还是几年是不支持sass,和less的, ...

  3. POJ-2104-Kth Number(主席树)

    链接: https://vjudge.net/problem/POJ-2104#author=malic 题意: 给定一个数组 a[1...n],数组元素各不相同,你的程序要对每次查询Q(i,j,k) ...

  4. 【NOIP2017提高组模拟12.24】B

    题目 现在你有N个数,分别为A1,A2,-,AN,现在有M组询问需要你回答.每个询问将会给你一个L和R(L<=R),保证Max{Ai}-Min{Ai}<=R-L,你需要找出并输出最小的K( ...

  5. 【leetcode】Valid Triangle Number

    题目: Given an array consists of non-negative integers, your task is to count the number of triplets c ...

  6. 3828. 三角形计数 3829. ZCC loves Isaac 3830. 字符消除

    3828 给定n个点的坐标(0<=xi,yi<=10000)求选出任意三个点能组成的三角形的总面积. 题解 太naive了 枚举三角形的y最小的点,把剩余的点按角度排序 然后随便算,可以用 ...

  7. spring boot 配置HTTPS

    spring boot 版本是<version>1.5.8.RELEASE</version> 1.配置文件里,看下不要有空格=[不要有空格] 2.别名 =========== ...

  8. springboot(十)使用LogBack作为日志组件

    简介: 企业级项目在搭建的时候,最不可或缺的一部分就是日志,日志可以用来调试程序,打印运行日志以及错误信息方便于我们后期对系统的维护,在SpringBoot兴起之前记录日志最出色的莫过于log4j了, ...

  9. MariaDB(Mysql)-主从搭建

    卸载过程: 停止服务:systemctl stop mariadb 查询安装包:rpm -qa | grep mariadb 卸载: rpm -e mariadb-server rpm -e mari ...

  10. 接口自动化request库入门

    requests库7个主要方法 r= requsts.get(),主要属性: r.raise_for_status()方法内部判断r.status_code是否等于200不需要增加额外的if语句,该语 ...