首先pom依赖
<!-- shiro核心包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <!-- shiro 引入缓存--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency> <!-- shiro标签,,thymeleaf支持shrio标签需要额外引用这个包--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>1.2.1</version> </dependency>
1.初步的拦截;
首先定义一个shiroconfig,,还有Realm,用于身份信息权限信息的验证。
ShiroConfig //首先定义shiro过滤器工厂类 @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不会被拦截的链接 顺序判断 filterChainDefinitionMap.put("/static/**", "anon"); //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/logout", "logout"); //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问,我这里是过滤前缀是user的--> filterChainDefinitionMap.put("/userInfo/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面;不止需要这个 还需要在异常拦截器里配置 //shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } //第二:SecurityManager,Shiro的安全管理,主要是身份认证的管理,缓存管理 @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); securityManager.setCacheManager(ehCacheManager()); //加入缓存管理(不用即不加) return securityManager; } @Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); //加入自定义密码匹配(不用即不加) return myShiroRealm; } 第三:Realm,用于身份信息权限信息的验证。 身份校验核心 MyShiroRealm extends AuthorizingRealm 实现两个方法 1 doGetAuthenticationInfo 主要是身份的校验 2 doGetAuthorizationInfo 设置权限信息 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("MyShiroRealm.doGetAuthenticationInfo()"); //获取用户的输入的账号. String username = (String)token.getPrincipal(); //通过username从数据库中查找 User对象,如果找到,没找到. //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 UserInfo userInfo = userInfoService.findByUsername(username); System.out.println("----->>userInfo="+userInfo); if(userInfo == null){ return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( userInfo, //用户名 userInfo.getPassword(),//密码 ByteSource.Util.bytes(userInfo.getSalt()), getName() //realm name ); return authenticationInfo; //根据authenticationInfo进行校验,,如果没有自定义密码配置 则CredentialsMatcher.doCredentialsMatch(token, info)实现明文校验 } 如果自定义密码配置 在config中 @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 采用MD5方式加密 hashedCredentialsMatcher.setHashAlgorithmName("MD5"); // 设置加密次数 hashedCredentialsMatcher.setHashIterations(1024); return hashedCredentialsMatcher; }
以上会进行拦截身份的校验
2.权限的校验
权限校验: @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); UserInfo userInfo = (UserInfo)principals.getPrimaryPrincipal(); for(SysRole role:userInfo.getRoleList()){ authorizationInfo.addRole(role.getRole()); for(SysPermission p:role.getPermissions()){ authorizationInfo.addStringPermission(p.getPermission()); } } return authorizationInfo; }首先config里开启注解的支持 /** * 开启shiro aop注解支持. * 使用代理方式;所以需要开启代码支持; * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } //然后控制器里 @RequiresPermissions("userInfo:view")//权限管理; @RequestMapping("/userList") @RequiresPermissions("userInfo:view")//权限管理; public String userInfo(){ System.out.println("1212---------------------------------------"); return "userInfo"; } //这样的话权限不够会抛出异常,所以还需 配置异常拦截器/** * 配置异常拦截器 权限不够的异常跳转页面 * @return */ @Bean(name="simpleMappingExceptionResolver") public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() { SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver(); Properties mappings = new Properties(); mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理 mappings.setProperty("UnauthorizedException","403"); r.setExceptionMappings(mappings); // None by default r.setDefaultErrorView("error"); // No default r.setExceptionAttribute("ex"); // Default is "exception" //r.setWarnLogCategory("example.MvcLogger"); // No default return r; }
3.如果thymeleaf想使用shiro标签 需要引用相应的pom
同时config中配置
@Beanpublic ShiroDialect shiroDialect() { return new ShiroDialect();}
html中引入相应标签库
<html lang="en" xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
4.使用shiro 缓存,首先引入相应的pom
在config中
@Bean public EhCacheManager ehCacheManager() { System.out.println("ShiroConfiguration.getEhCacheManager()"); EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml"); return cacheManager; }
AuthorizingRealm 身份校验的核心类,这里摘一段源码 看下这个大概是如何实现的
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } AuthorizationInfo info = null; if (log.isTraceEnabled()) { log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache(); if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } Object key = getAuthorizationCacheKey(principals); info = cache.get(key); if (log.isTraceEnabled()) { if (info == null) { log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } if (info == null) { // Call template method if the info was not found in a cache info = doGetAuthorizationInfo(principals); // If the info is not null and the cache has been created, then cache the authorization info. if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); cache.put(key, info); } } return info; }
不难看出,在获取权限的方法中,首先是先从缓存中读取AuthorizationInfo,如果缓存中不存在 才访问doGetAuthorizationInfo(获取权限并将之存放进缓存中)
5.权限更新的同时,清楚缓存里的权限
当时是看了很多网上的案例,发现都不可行,自己参照上述的源码,了解缓存大概是怎么实现的 代码如下
public void reloadAuthorizing(){ Subject subject = SecurityUtils.getSubject(); Object key = getAuthorizationCacheKey(subject.getPrincipals());//看下当前是否有权限缓存 clearCachedAuthorizationInfo(subject.getPrincipals()); }
关于注解RequiresPermissions
源码大概看了一部分,也参考了网上的例子 感觉人家讲的更好 我把参考的路径贴出来 http://blog.csdn.net/jin5203344/article/details/53187923
最后github地址 https://github.com/wuhao1994/testshiro
ShiroConfig//首先定义shiro过滤器工厂类@Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不会被拦截的链接 顺序判断 filterChainDefinitionMap.put("/static/**", "anon"); //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/logout", "logout"); //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问,我这里是过滤前缀是user的--> filterChainDefinitionMap.put("/userInfo/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面;不止需要这个 还需要在异常拦截器里配置 //shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }//第二:SecurityManager,Shiro的安全管理,主要是身份认证的管理,缓存管理 @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; }@Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; }
来源:https://www.cnblogs.com/wuhaobk/p/8385197.html