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

相关文章
相关标签/搜索