Spring-boot2整合Shiro 并开启Shiro权限标签

之前一直对spring-boot没有配置文件的说法很好奇, 一直想怎么可能呢, 一个项目那么大,集成的技术框架那么多, 没有配置文件spring-boot它怎么知道该怎么做,难道他是神一样的存在,

 通过这几天对spring-boot的研究发现, 之前说spring-boot 零配置 消灭配置文件的说法, 就感觉是换汤不换药, 新瓶装旧酒一样

只是把xml的配置文件 换成了用java类+注解的方式来实现了, 自已感觉这种方式还倒退回去了, 用起来很麻烦, 没有单独使用spring那么好用,灵活, 个人还是喜欢使用spring + mvc

 

下面将本人将Spring-boot2整合Shiro 并开启Shiro权限标签的代码帖一下, 留个记念

1.加入依赖 

   
            org.apache.shiro
            shiro-web
            ${shiro.version}
        
        
            org.apache.shiro
            shiro-spring
            ${shiro.version}
        
        
            org.apache.shiro
            shiro-core
            ${shiro.version}
            
                
                    slf4j-api
                    org.slf4j
                
            
        

2.自定义realm 实现  org.apache.shiro.realm.AuthorizingRealm 进行身份跟权限验证

package com.dance.admin.security;

import com.dance.common.util.StringUtil;
import com.dance.enums.ShiroRoleEnum;
import com.dance.model.ShiroPerm;
import com.dance.model.ShiroUser;
import com.dance.pojo.ShiroUserPO;
import com.dance.service.ShiroPermService;
import com.dance.service.ShiroUserService;
import com.dance.util.SessionKit;
import com.dance.util.SessionShiro;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
 *
 * @developers LONGZHIQIANG
 * @createtime 2019-07-01 11:47.
 * @describe    shiro安全认证自定义规则
 * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
 */
@Slf4j
@Component
public class ShiroDbRealm extends AuthorizingRealm {

    //页面在session中获取用户菜单时的key
    public static String PERMISSIONS_KEY = "permissions";

    @Autowired
    private ShiroUserService shiroUserService;

    @Autowired
    private ShiroPermService shiroPermService;


    /**
     * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
     * 采用构造方法初使化设定 realm的相关参数
     * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
     */
    ShiroDbRealm(){
        this("MD5",1024);
        this.setCachingEnabled(true);
        this.setAuthenticationCachingEnabled(false);
        this.setAuthorizationCachingEnabled(true);
    }

    ShiroDbRealm(String hashAlgorithmName, Integer hashIterations){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(hashAlgorithmName);
        matcher.setHashIterations(hashIterations);
        this.setCredentialsMatcher(matcher);
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        //1、根据用户名查询用户
        ShiroUserPO user = userGetByName(token.getUsername());
        //2、当用户角色为超级管理员则获取系统所有菜单(该角色所属权限数据库没有映射数据,默认拥有为所有权限)
        if (user.getRoleIdSet().contains(ShiroRoleEnum.SUPERADMIN.getId().toString())) {
            List perms = shiroPermService.selectAll();
            user.setPerms(new HashSet<>(perms));
        }
        //3、将系统后台菜单存入用户sessiom
        List permList = user.getPerms().stream().sorted(Comparator.comparing(ShiroPerm::getPermCode)).collect(Collectors.toList());
        SessionKit.setAttribute(PERMISSIONS_KEY, permList);
        ByteSource salt = ByteSource.Util.bytes(user.getSalt());
        return new SimpleAuthenticationInfo(new SessionShiro(user), user.getPin(), salt, getName());
    }


    /**
     * 授权查询回调函数, 进行鉴权同时缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SessionShiro user = (SessionShiro) principals.getPrimaryPrincipal();
        if (StringUtil.isEmpty(user)) { return null; }
        SimpleAuthorizationInfo simpleInfo = new SimpleAuthorizationInfo();
        ShiroUserPO po = userGetByName(user.name);
        simpleInfo.addRoles(po.getRoleIdSet());

        if (po.getRoleIdSet().contains(ShiroRoleEnum.SUPERADMIN.getId().toString())) {
            List all = shiroPermService.selectAll();
            List permissions = all.stream().map(ShiroPerm::getPermPermission).collect(Collectors.toList());
            simpleInfo.addStringPermissions(permissions);
        } else {
            simpleInfo.addStringPermissions(po.getPermIdSet());
        }
        return simpleInfo;
    }

    //根据用户名根据用户相关信息
    private ShiroUserPO userGetByName(String name) {
        List pos = shiroUserService.queryLinkPrem(new ShiroUser().setName(name));
        if (StringUtil.isEmpty(pos)) {
            throw new IncorrectCredentialsException();
        }
        if (pos.size() > 1) {
            log.error("用户数据异常,帐号 {} 查询到多个相同帐户", name);
            throw new IncorrectCredentialsException();
        }
        return pos.get(0);
    }
}

3.定义配置类 这个配置文件以前就是一个 application-shiro.xml, 只是用java代码的方法去实现而以 新瓶装旧酒

package com.dance.admin.security;

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.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;

/**
 * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
 *
 * @developers LONGZHIQIANG
 * @createtime 2019-07-01 10:26.
 * @describe    shiro 全局配置类
 * ☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆☆☆★☆☆☆☆
 */
@Configuration
public class ShiroDbConfig {

    /**
     *  初使化安全管理器
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager initDefaultWebSecurityManager(@Qualifier("shiroDbRealm") ShiroDbRealm shiroDbRealm){
        DefaultWebSecurityManager security = new DefaultWebSecurityManager();
        security.setRealm(shiroDbRealm);
        return security;
    }

    /**
     *  初使化shiroFilter处理路径相关设置
     */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
		ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        //身份认证失败[未登入],则跳转到登录页面 在controller定这个路径直接转发到首页
        filter.setLoginUrl("/");
		filter.setSecurityManager(securityManager);
		filter.setFilterChainDefinitionMap(new LinkedHashMap(){
			{
				put("/logout", "logout");
				put("/logout", "logout");
				put("/IOCloud/**", "authc");
				put("/admin/**", "authc");
				put("/**", "anon");
			}
		});
		return filter;
	}


    /***
     * 保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

	/**
     * 开启Shiro的注解java注解,
     * 需借助SpringAOP扫描使用Shiro注解的类
     * 并在必要时进行安全逻辑验证
     */
    @Bean(name = "authorizationAttributeSourceAdvisor")
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager);
        return sourceAdvisor;
    }



  /**
     * 解决与SiteMesh与shiro filter冲突导致 jsp页面 shiro标签无效问题
     *      SiteMeshFilter在处理时,调用了context.decorate(decoratorPath, content),
     *      这导致了ApplicationDispatcher.forward操作
     *      forward操作里,又重新构建filter chain:
     *      Shiro Filter,刚好排在SiteMeshFilter之后,
     *      于是在Forward之前和之后都没有执行。
     * 该解决方案来源于该播客 https://blog.csdn.net/elashu/article/details/85089891
     */
    @Bean
    public FilterRegistrationBean delegatingFilterProxy() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        filterRegistrationBean.setEnabled(true);
        filterRegistrationBean.addUrlPatterns("/*");
        //filterRegistrationBean.setAsyncSupported(true);

        EnumSet types = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
        filterRegistrationBean.setDispatcherTypes(types);
        return filterRegistrationBean;
    }

}

 

4.搞定收工

 

 

 

 

你可能感兴趣的:(spring-mvc,java)