SpringBoot-Shiro 框架集成

在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

相關文章
相關標籤/搜索