项目基本配置参考SpringBoot入门一,使用myEclipse新建一个SpringBoot项目,使用myEclipse新建一个SpringBoot项目即可。现在来给项目添加shiro支持,数据暂时硬编码,不连接数据库,具体内容如下:

1. pom.xml添加以下配置信息

	<!-- 开启shiro依赖 -->
	<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring-boot-starter</artifactId>
			<version>1.4.0</version>
	</dependency>

2. 创建shiro配置文件

2.1 自定义权限过滤器
	package com.qfx.demo.shiro;

	import javax.servlet.ServletRequest;
	import javax.servlet.ServletResponse;
	import javax.servlet.http.HttpServletRequest;

	import org.apache.logging.log4j.LogManager;
	import org.apache.logging.log4j.Logger;
	import org.apache.shiro.subject.Subject;
	import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;

	import com.qfx.demo.vo.SysUser;

	/**
	 * @功能描述:	拦截控制,用于替换shiro默认的roles拦截规则,改"并且(and)"为"或者 (or)"
	 */
	public class CustomRolesAuthorizationFilter extends RolesAuthorizationFilter {
		private final Logger logger = LogManager.getLogger(getClass()); 
		/**
			 * Overriding
			 * @功能描述:设置同一个URL配置多个角色为"或者"的关系,默认为"并且",
			 * 					如:/user/** = Role["admin,user"],默认必须满足"admin","user"条件,
			 * 			       改为"或者"之后只需要满足一个条件即可(Ini.Section中有此url,会走此方法)
			 * @param request
			 * @param response
			 * @param obj
			 * @return
			 * @throws Exception
			 */
		@Override
		public boolean isAccessAllowed(ServletRequest request,ServletResponse response, Object obj) {
			Subject subject = getSubject(request, response);
			// 验证是否登录
			if (null == subject.getPrincipals()) {
				return false;
			}
			// 获取请求地址
			HttpServletRequest hsq = (HttpServletRequest) request;
			String requestUrl = hsq.getServletPath();
			// 获取用户信息,这里返回的对象类型与登录验证时
			// new SimpleAuthenticationInfo(user, pwd, this.getName())中的第一个参数的类型需要保持一致
			SysUser user = (SysUser)subject.getPrincipals().getPrimaryPrincipal();

			System.out.println("--------1.开启用户["+user.getUserName()+"]访问["+requestUrl+"]的角色过滤--------");

			// 获取角色信息
			String[] rolesArray = (String[]) obj;
			if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问
				System.out.println("--------3.用户["+user.getUserName()+"]访问["+requestUrl+"]的角色过滤结束--------");
				logger.info("用户["+user.getUserName()+"]访问["+requestUrl+"]无角色限制,权限验证通过!");
					return true;
			}    
			for (int i = 0; i < rolesArray.length; i++) {    
					if (subject.hasRole(rolesArray[i])) { //若当前用户是rolesArray中的任何一个,则有权限访问  
						System.out.println("--------3.用户["+user.getUserName()+"]访问["+requestUrl+"]的角色过滤结束--------");
						logger.info("用户["+user.getUserName()+"]访问["+requestUrl+"]权限验证通过!");
							return true;    
					}    
			}
			System.out.println("--------3.用户["+user.getUserName()+"]访问["+requestUrl+"]的角色过滤结束--------");
			logger.info("用户["+user.getUserName()+"]访问["+requestUrl+"]权限验证失败,禁止访问!");
			return false;
		}
	}
2.2 自定义realm
	package com.qfx.demo.shiro;

	import java.util.HashSet;
	import java.util.Set;

	import org.apache.shiro.authc.AuthenticationException;
	import org.apache.shiro.authc.AuthenticationInfo;
	import org.apache.shiro.authc.AuthenticationToken;
	import org.apache.shiro.authc.SimpleAuthenticationInfo;
	import org.apache.shiro.authc.UnknownAccountException;
	import org.apache.shiro.authz.AuthorizationInfo;
	import org.apache.shiro.authz.SimpleAuthorizationInfo;
	import org.apache.shiro.realm.AuthorizingRealm;
	import org.apache.shiro.subject.PrincipalCollection;
	import org.apache.shiro.util.ByteSource;

	import com.qfx.demo.cache.UserCache;
	import com.qfx.demo.vo.SysUser;

	public class UserRealm extends AuthorizingRealm {
		/**
			 * Overriding
			 * @功能描述:	权限验证
			 * @param arg0
			 * @return
			 */
		@Override
		protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
			// 1.获取用户信息
			//   这里principals.getPrimaryPrincipal()的返回的对象类型与登录验证时
			//   new SimpleAuthenticationInfo(user, pwd, this.getName())中的第一个参数的类型需要保持一致
			SysUser user = (SysUser)principals.getPrimaryPrincipal();
			System.out.println("--------2.用户["+user.getUserName()+"]进行权限验证--------");
			// 2.单独定一个集合对象放置角色信息 
			Set<String> roles = new HashSet<String>();
			roles.add(user.getRoleName());
			// 3.查到权限数据,返回授权信息(要包括 上边的permissions)  
			SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
			return simpleAuthorizationInfo;
		}

		/**
			 * Overriding
			 * @功能描述:	登陆验证
			 * @param arg0
			 * @return
			 * @throws AuthenticationException
			 */
		@Override
		protected AuthenticationInfo doGetAuthenticationInfo(
				AuthenticationToken token) throws AuthenticationException {
			System.out.println("---------用户登录验证---------");
			// 1.获取登录名称
			String userName = token.getPrincipal().toString();
			// 2.根据登录名称获取用户信息(从缓存获取,正式项目从数据库)
			SysUser user = UserCache.getUserCacheMap(userName);
			if (null == user) {
				// 抛出账户不存在的异常
				throw new UnknownAccountException();
			}
			// 3.获取查询到到密码和盐值
			String pwd = user.getPassWord();
			String salt = user.getSalt();
			// 4.交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
			//   new SimpleAuthenticationInfo(user, pwd, this.getName())中的user是SysUser对象,在其他接收的地方也要转成SysUser对象
			SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, pwd, this.getName());  
			// 设置盐值(salt = pwd+userName + salt)
			authcInfo.setCredentialsSalt(ByteSource.Util.bytes(pwd+userName + salt));
			return authcInfo; 
		}
	}
2.3 自定义shiro核心配置类(取代xml配置文件)
	package com.qfx.demo.shiro;

	import java.util.LinkedHashMap;
	import java.util.Map;

	import javax.servlet.Filter;

	import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
	import org.apache.shiro.mgt.SecurityManager;
	import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
	import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
	import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
	import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;

	import com.qfx.demo.cache.MenuRoleCache;
	import com.qfx.demo.vo.SysMenuRole;

	@Configuration
	public class ShiroConfig {
		/**
			 * <h5>功能:凭证匹配器</h5>
			 * @return 
			 */
		@Bean
		public HashedCredentialsMatcher hashMatcher(){
				HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
				//采用md5加密,没有默认值.可以有MD5或者SHA-1,如果对密码安全有更高要求可以用SHA-256或者更高
				hashedCredentialsMatcher.setHashAlgorithmName("md5");
				//散列的次数,比如散列2次,相当于md5(md5(""));
				hashedCredentialsMatcher.setHashIterations(2);
				//默认是true,true时用的是Hex编码;false时用Base64编码
				hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
				return hashedCredentialsMatcher;
		}

		/**
			 * <h5>功能:配置shiro session 的一个管理器</h5>
			 * @return 
			 */
		@Bean
		public DefaultWebSessionManager sessionManager(){
			DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
			defaultWebSessionManager.setSessionDAO(new MemorySessionDAO());
			// 隐藏在地址栏中显示的JSESSIONID
			defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);
			// session的失效时长,单位毫秒(这里设置为30分钟,实际项目请自行修改)
			defaultWebSessionManager.setGlobalSessionTimeout(1800000);
			// 间隔一定时间清理失效会话,单位毫秒(这里设置为每5分钟清理一次用户直接关闭浏览器造成的孤立会话,实际项目请自行修改)
			defaultWebSessionManager.setSessionValidationInterval(300000);
			// 描session线程,负责清理超时会话
			defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
			return defaultWebSessionManager;
		}

		/**
			* <h5>功能:自定义realm认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理</h5>
			* @param hashMatcher
			* @return 
			*/
		@Bean
		public UserRealm userRealm(HashedCredentialsMatcher hashMatcher){
		UserRealm userRealm = new UserRealm();
		userRealm.setCredentialsMatcher(hashMatcher);
		return userRealm;
		}

		/**
			* <h5>功能:安全管理器</h5>
			* 权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类
			* @param userRealm
			* @param sessionManager
			* @return 
			*/
		@Bean
		public DefaultWebSecurityManager securityManager(UserRealm userRealm, DefaultWebSessionManager sessionManager){
				DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
				// 自定义realm
				securityManager.setRealm(userRealm);
				// shiro 会话管理
				securityManager.setSessionManager(sessionManager);
				return securityManager;
		}

		/**
			 * <h5>功能:自定义权限过滤器</h5>
			 * @param securityManager
			 * @return 
			 */
		@Bean
		public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
			ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
			// 调用我们配置的安全管理器
			shiroFilterFactoryBean.setSecurityManager(securityManager);
			// 配置我们的登录请求地址,非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
			shiroFilterFactoryBean.setLoginUrl("/view/error/401.jsp");
			// 设置无权限时跳转的URL
			shiroFilterFactoryBean.setUnauthorizedUrl("/view/error/403.jsp");

			Map<String, Filter> filter = shiroFilterFactoryBean.getFilters();
			filter.put("roles", new CustomRolesAuthorizationFilter());

			// 设置拦截器
			Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
			shiroFilterFactoryBean.setFilters(filter);

			// 对静态资源设置匿名访问,从resoutces/static后面开始写
			filterChainDefinitionMap.put("/css/**", "anon");
			// 可匿名访问的地址
			filterChainDefinitionMap.put("/", "anon");
			filterChainDefinitionMap.put("/index.jsp", "anon");
			filterChainDefinitionMap.put("/login/loginPage", "anon");
			filterChainDefinitionMap.put("/login/register", "anon");
			filterChainDefinitionMap.put("/login/login", "anon");
			// 请求 logout.do地址,shiro去清除session
			filterChainDefinitionMap.put("/logout", "logout");

			//循环url,逐个添加到section中。section就是filterChainDefinitionMap,
			//里面的键就是链接URL,值就是存在什么条件才能访问该链接
			Map<String, SysMenuRole> menuRoleMap = MenuRoleCache.menuRoleCacheMap;
			for (String key : menuRoleMap.keySet()) {
				filterChainDefinitionMap.put(key, "roles["+menuRoleMap.get(key).getRoleNames()+"]");
			}

			//所有url都必须认证通过才可以访问,必须放在最后
			filterChainDefinitionMap.put("/**", "authc");
			shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
			return shiroFilterFactoryBean;
		}
	}

3.其他文件 javaBean文件和缓存类等信息就不从这里贴出来了,核心的就是上面的几个文件,想要应用的话,只要把对应的获取数据的地方修改成自己的实现就可以了。