一.认识shiro
为什么需要权限控制?
- 我们知道系统中通常具有很多的功能,并不是每一个人登录之后都可以进行访问,我们登录系统之后根据身份不同,系统分给登陆者不同的访问权限,这其实就是权限控制
权限控制中的两个概念:
- 认证:认证就是系统提供识别我们身份的功能,告诉系统我们是谁?
- 授权:授权其实是系统根据我们是谁分配相应的访问权力,告诉我们,我们能干什么?
shiro是Apache提供的一个安全框架,主的功能是对权限的管理,通常对权限的控制有以下几个方案:
- URL拦截:是通过对访问路径的拦截,而进行对权限的控制
- 注解方式:注解方式是通过生成Action的代理对象,然后当访问Action的时候判断是否有方法注解,进一步进行权限控制
- 页面标签:通过标签的方式对系统的菜单或者按钮进行隐藏达到权限控制
权限控制模型:
shiro框架的下载:
- Shiro.apache.org进行下载
- 下载shiro-all-xxx的jiar包导入
Shiro框架运行原理
- AppicationCode使我们的应用程序,由程序员维护
- Subject当表当前的登录用户
- SecurityManager是shiro的安全管理器,管理用户的认证和授权
- Realm:安全数据桥,与DAO进行交互
二.在项目中使用shiro框架:
第一步:将shiro的jar包导入到项目中
第二步:在web.xml中配置一个过滤器对象,在项目启动时到spring工厂中加载一个和当前过滤器name同名的bean对象
<!-- 配置Shiro框架的过滤器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
第三步:在spring配置文件中配置一个名称为shiroFilter的bean
<!-- 配置shiro的Bean --> <bean name="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 配置安全管理器 --> <property name="securityManager" ref="securityManager"></property> <!-- 配置登录页面url --> <property name="loginUrl" value="/login.jsp"></property> <!-- 配置认证成功后的首页 --> <property name="successUrl" value="/index.jsp"></property> <!-- 配置权限认证失败的页面 --> <property name="unauthorizedUrl" value="unauthorized.jsp"></property> <!-- 配置url的拦截 --> <property name="filterChainDefinitions"> <value> /css/** = anon /images/** = anon /js/** = anon /validatecode.jsp* = anon /login.jsp = anon /userAction_login = anon /** = authc </value> </property> </bean> <!-- 配置安全管理器 --> <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="bosRealm"></property> <property name="cacheManager" ref="cacheManager"></property> </bean>
第四步:修改UserAction的login登录访问,使用shiro框架提供的方式进行认证操作
第五步:自定义一个Realm,进行认证和授权操作/** * 用户登录功能 * * @return */ public String login() { //获取session中的对象 User hasLogin = (User) ActionContext.getContext().getSession().get("existUser"); if(hasLogin != null) { //如果已经登录,则直接返回首页 return "index"; } else { //获取session中的验证码 String validateCode = (String) ActionContext.getContext().getSession().get("key"); if(StringUtils.isBlank(checkcode) || !checkcode.equals(validateCode)) { //如果验证码错误 this.addActionError(this.getText("validateCodeErr")); return "login"; } else { //验证码正确的时候交给shiro框架进行认证 String username = model.getUsername(); String password = model.getPassword(); password = MD5Utils.md5(password); //shiro获取当前用户 Subject subject = SecurityUtils.getSubject(); AuthenticationToken token = new UsernamePasswordToken(username,password); try { subject.login(token); User existUser = (User) subject.getPrincipal(); //登录成功 ActionContext.getContext().getSession().put("existUser", existUser); } catch (UnknownAccountException e) { e.printStackTrace(); this.addActionError("用户名不存在"); return "login"; } catch (Exception e) { e.printStackTrace(); this.addActionError("用户名或者密码错误"); return "login"; } return "index"; } } }
第六步:在spring配置文件中注册上面的realm,并注入给安全管理器/** * BOSRealm * * @author YUAN.PAN * @version 1.0 2016-12-12 20:25:55 */ public class BOSRealm extends AuthorizingRealm{ /** 注入UserDao */ @Resource private IUserDao userDaoImpl; /** 注入权限Dao */ @Resource private IFunctionDao functionDaoImpl; /** * 授权方法 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获取当前的登录用户进行授权 User user = (User) principal.getPrimaryPrincipal(); List<Function> list = null; if(user.getUsername().equals("admin")) { list = functionDaoImpl.findAll(); } else { list = functionDaoImpl.findByUserId(user.getId()); } //添加权限 for (Function fun : list) { info.addStringPermission(fun.getCode()); } return info; } /** * 认证方法 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //将token进行转换 UsernamePasswordToken upToken = (UsernamePasswordToken)token; String username = upToken.getUsername(); char[] password = upToken.getPassword(); //根据用户名查询User对象 User user = userDaoImpl.findUserByUsername(username); if(user == null) { return null; } else { SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName()); return info; } } }
<!-- Realm --> <bean name="bosRealm" class="cn.itcast.bos.shiro.BOSRealm"></bean>
三.使用Ehcache缓存权限数据
第一步:将EHcache的jar包复制到项目中
第二步在项目类路径下提供Ehcache的配置文件,可以从jar包中获得
第三步:在Spring中配置缓存管理器注入给安全管理器即可
<!-- 配置安全管理器 --> <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="bosRealm"></property> <!-- 缓存管理器 --> <property name="cacheManager" ref="cacheManager"></property> </bean> <!-- 配置缓存管理器 --> <bean name="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property> </bean>