在SpringBoot中使用Shiro安全框架配置方案:css
1,首先引入Shiro的Maven jar包:html
<!-- 权限框架 begin--> <dependency><!-- 核心 --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <dependency><!-- 集成Spring --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency><!-- 缓存机制 --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.0</version> </dependency> <!-- 权限框架 end-->
2,引入Shiro缓存配置:java
<!-- 在resource下新建 ehcache-shiro.xml --> <ehcache updateCheck="false" name="shiroCache"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"/> </ehcache>
3,进行Shiro配置:git
(1),自定义受权认证:web
package com.gy.demo.config.shiro; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.gy.demo.entity.Power; import com.gy.demo.entity.User; import com.gy.demo.entity.UserLogin; import com.gy.demo.service.RolePowerService; import com.gy.demo.service.UserLoginService; import com.gy.demo.service.UserService; import jdk.nashorn.internal.parser.Token; 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.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.SecurityUtils; import org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; import java.util.*; /** * Description : 自定义的 Shiro 认证受权 * * 域,Shiro从Realm获取安全数据(如用户、角色、权限), * 就是说SecurityManager要验证用户身份, * 那么它须要从Realm获取相应的用户进行比较以肯定用户身份是否合法; * 也须要从Realm获得用户相应的角色/权限进行验证用户是否能进行操做; * 能够把Realm当作DataSource,即安全数据源; * * Created by com on 2017/12/14 * * @author geYang **/ public class AuthorRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(AuthorRealm.class); @Resource private UserService userService; @Resource private UserLoginService userLoginService; @Resource private RolePowerService rolePowerService; /** * 认证(登陆时调用) 获取身份验证信息 * */ @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("Shiro: 进行身份验证"); String accessToken = (String) authenticationToken.getPrincipal(); //根据accessToken,查询用户信息 User user = userService.selectOne(new EntityWrapper<User>().eq("phone", accessToken)); if(user==null){ return null; } //获取用户登陆密码 UserLogin userLogin = userLoginService.selectById(user.getId()); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,userLogin.getPassword(), ByteSource.Util.bytes(user.getPhone()),"AuthorRealm"); return simpleAuthenticationInfo; } /** * 受权(验证权限时调用) 根据用户身份获取受权信息 * */ @Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principalCollection) { logger.info("Shiro: 进行权限验证"); //获取用户信息 User user = principalCollection.oneByType(User.class); //获取到用户权限列表 List<Power> rolePowerList = rolePowerService.getRolePower(user.getRoleId()); Set<String> powerCodeSet = new HashSet<>(); Iterator<Power> it = rolePowerList.iterator(); while (it.hasNext()){ powerCodeSet.add(it.next().getCode()); } List<String> powerCodeList = new ArrayList<>(); powerCodeList.addAll(powerCodeSet); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addStringPermissions(powerCodeList); return simpleAuthorizationInfo; } }
(2),注入配置算法
package com.gy.demo.config.shiro; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import java.util.LinkedHashMap; import java.util.Map; /** * Description : Shiro 权限框架配置 * * --------------------------------------------------------- * 一、应用代码经过Subject来进行认证和受权, * 而Subject又委托给SecurityManager; * * 二、咱们须要给Shiro的SecurityManager注入Realm, * 从而让SecurityManager能获得合法的用户及其权限进行判断。 * --------------------------------------------------------- * @since 2017/12/14 * @author geYang **/ @Configuration public class ShiroConfig { private Logger logger = LoggerFactory.getLogger(ShiroConfig.class); /** * TODO 过滤文件 * @param securityManager 安全机制 * @return ShiroFilterFactoryBean * @since 2017/12/18 10:07 * @author geYang */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { logger.info("Shiro: 开启拦截验证"); ShiroFilterFactoryBean shirFilter = new ShiroFilterFactoryBean(); // SecurityManager shirFilter.setSecurityManager(securityManager); // 登录页面 shirFilter.setLoginUrl("/login"); // 登陆成功后要跳转的连接 shirFilter.setSuccessUrl("/index"); // 未受权界面 shirFilter.setUnauthorizedUrl("/500.html"); // 拦截器 Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>(); // 配置退出过滤器,其中的具体的退出代码 Shiro 已经替咱们实现了 filterChainDefinitionMap.put("/logout", "logout"); // 过滤链 filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); // 登陆页面 filterChainDefinitionMap.put("/login", "anon"); // 登陆提交数据 filterChainDefinitionMap.put("/admin/adminLogin", "anon"); // 注册界面 filterChainDefinitionMap.put("/user/register.html", "anon"); // 注册提交数据 filterChainDefinitionMap.put("/admin/register", "anon"); // 发送邮箱验证码 filterChainDefinitionMap.put("/admin/sencCode", "anon"); // 判断用户名是否存在 filterChainDefinitionMap.put("/admin/isUsername/**", "anon"); // 判断邮箱是否存在 filterChainDefinitionMap.put("/admin/isEmail/**", "anon"); // 公共数据 filterChainDefinitionMap.put("/public/**", "anon"); // 其余 filterChainDefinitionMap.put("/**", "authc"); /* * * anon:全部url都均可以匿名访问; * authc: 须要认证才能进行访问; * user:配置记住我或认证经过能够访问; * */ shirFilter.setFilterChainDefinitionMap(filterChainDefinitionMap); return shirFilter; } /** * TODO 核心安全管理器;即全部与安全有关的操做都会与SecurityManager交互; *------------------------------------------------------------------------ * SecurityManager 至关于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher; * 是Shiro的心脏;全部具体的交互都经过 SecurityManager 进行控制; * 它管理着全部Subject、且负责进行认证和受权、及会话、缓存的管理。 *------------------------------------------------------------------------- * @return SecurityManager * @since * @author geYang */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm()); securityManager.setCacheManager(ehCacheManager()); return securityManager; } /** * 身份认证realm * */ @Bean public AuthorRealm myRealm(){ AuthorRealm myRealm = new AuthorRealm(); myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myRealm; } /** * 凭证匹配器 * (因为咱们的密码校验交给 shiro 的SimpleAuthenticationInfo进行处理了 * 因此咱们须要修改下doGetAuthenticationInfo中的代码;) * @return HashedCredentialsMatcher */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ logger.info("Shiro: 开启凭证匹配器"); HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashAlgorithmName("MD5"); // 散列的次数,好比散列两次,至关于 md5(md5("")); hashedCredentialsMatcher.setHashIterations(1); return hashedCredentialsMatcher; } /** * 缓存机制 * */ @Bean public EhCacheManager ehCacheManager(){ logger.info("Shiro: 开启缓存机制"); EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return cacheManager; } /** * Shiro生命周期处理器 * @return */ @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { logger.info("Shiro: 生命周期处理"); return new LifecycleBeanPostProcessor(); } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全 * 逻辑验证 * 配置如下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)便可实现此功能 * @return */ @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { logger.info("Shiro: 开启shiro注解"); DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); proxyCreator.setProxyTargetClass(true); return proxyCreator; } /** * shiro注解支持 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { logger.info("Shiro: 开启shiro注解支持"); AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }
SpringBoot官方文档: https://docs.spring.io/spring-boot/docs/current/reference/html/spring
项目源码: https://gitee.com/ge.yang/SpringBootapache