Shiro在线刷新权限

shiro-spring-boot-web-starter 1.6.0版本[SpringBoot微服务框架]
提前说好,说我缺文件的,一般那是不中要的

ShiroFreshService


    /**
     * 初始化权限 -> 拿全部权限
     *
     * @param :
     * @return: java.util.Map<java.lang.String, java.lang.String>
     */
    Map<String, String> loadFilterChainDefinitionMap();


    /**
     * 重新构建权限过滤器
     * 一般在修改了用户角色、用户等信息时,需要再次调用该方法
     */
    void reCreateFilterChains(ShiroFilterFactoryBean shiroFilterFactoryBean);

ShiroFreshServiceImpl

@Slf4j
@Service
public class ShiroFreshServiceImpl implements ShiroFreshService {

    @Autowired
    private RoleMenuService roleMenuService;

    @Autowired
    private ConfigProperties configProperties;

    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static Lock writeLock = readWriteLock.writeLock();

    @Override
    public Map<String, String> loadFilterChainDefinitionMap() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/validcaptcha", "anon");//验证验证码
        filterChainDefinitionMap.put("/validate", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/logout", "anon");
        filterChainDefinitionMap.put("/css/** ", "anon");
        filterChainDefinitionMap.put("/image/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/error/**", "anon");
        filterChainDefinitionMap.put("/plugins/**", "anon");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/401", "anon");
        filterChainDefinitionMap.put("/403", "anon");
        filterChainDefinitionMap.put("/404", "anon");
        filterChainDefinitionMap.put("/500", "anon");
        List<UrlRoleVo> urlRoleVoList = roleMenuService.findAllUrlRolesList();
        String roleCode = configProperties.getAdminRoleCode();
        if (CollectionUtils.isNotEmpty(urlRoleVoList)) {
            urlRoleVoList.forEach(ur -> filterChainDefinitionMap.put(ur.url(), "roles[" + ur.role().toUpperCase() + "," + roleCode + "]"));
        }
        //对所有用户认证
        filterChainDefinitionMap.put("/**", "authc");
        return filterChainDefinitionMap;
    }

    @Override
    public void reCreateFilterChains(ShiroFilterFactoryBean shiroFilterFactoryBean) {
        writeLock.lock();
        try {
            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                log.error("ShiroFreshServiceImpl刷新权限异常", e);
                throw new HdapException(GET_SHIRO_FILTER);
            }
            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager filterChainManager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
            //加载数据
            Map<String, String> filterChainDefinitionMap = loadFilterChainDefinitionMap();
            // 清空老的权限控制
            filterChainManager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            // 重新构建生成
            for (Map.Entry<String, String> filterChainDefinition : filterChainDefinitionMap.entrySet()) {
                filterChainManager.createChain(filterChainDefinition.getKey(), filterChainDefinition.getValue());
            }
        } finally {
            writeLock.unlock();
        }
    }
}

Config

/**
 * 参考【仅作参考】
 * 1. https://blog.youkuaiyun.com/New_Yao/article/details/100769385
 * 2. https://www.cnblogs.com/zhengqing/p/11603824.html
 * *.https://shiro.apache.org/spring-boot.html
 */
@Slf4j
@Configuration
public class SysUserSecurityConfig {

    @Value("${server.servlet.session.timeout}")
    @DurationUnit(ChronoUnit.SECONDS)
    private Duration timeout = Duration.ofMinutes(30L);

    @Autowired
    private ShiroFreshService shiroFreshService;

    /**
     * 设置用于匹配密码的CredentialsMatcher
     * SHA-256
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher credentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法,这里使用更安全的sha256算法
        credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        // 散列迭代次数
        credentialsMatcher.setHashIterations(1024);
        return credentialsMatcher;
    }

    /**
     * 配置自定义Realm
     *
     * @return
     */
    @Bean
    public SysUserRealm sysUserRealm() {
        SysUserRealm sysUserRealm = new SysUserRealm();
        // 配置使用哈希密码匹配
        sysUserRealm.setCredentialsMatcher(credentialsMatcher());
        // 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
        sysUserRealm.setAuthenticationCachingEnabled(true);
        // 启用授权缓存,即缓存AuthorizationInfo信息,默认false,一旦配置了缓存管理器,授权缓存默认开启
        sysUserRealm.setAuthorizationCachingEnabled(true);
        return sysUserRealm;
    }

    /**
     * 内存中的缓存管理器
     *
     * @return
     */
    @Bean
    protected CacheManager cacheManager() {
        return new MemoryConstrainedCacheManager();
    }

    /**
     * 配置会话管理器,设定会话超时及保存
     *
     * @return
     */
    @Bean("sessionManager")
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //全局会话超时时间(单位毫秒),默认30分钟
        sessionManager.setGlobalSessionTimeout(timeout.getSeconds() * 1000);
        //是否开启删除无效的session对象  默认为true
        sessionManager.setDeleteInvalidSessions(true);
        //是否开启定时调度器进行检测过期session 默认为true
        sessionManager.setSessionValidationSchedulerEnabled(true);
        //设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
        //设置该属性 就不需要设置 ExecutorServiceSessionValidationScheduler 底层也是默认自动调用ExecutorServiceSessionValidationScheduler
        //暂时设置为 5秒 用来测试
        // sessionManager.setSessionValidationInterval(5000);
        //禁用URL会话重写
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;

    }

    /**
     * 安全控制中心
     *
     * @return
     */
    @Bean("securityManager")
    public SessionsSecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        //配置自定义Realm
        defaultSecurityManager.setRealm(sysUserRealm());
        //内存中的缓存管理器
        defaultSecurityManager.setCacheManager(cacheManager());
        //配置会话管理器,设定会话超时及保存
        defaultSecurityManager.setSessionManager(sessionManager());
        return defaultSecurityManager;
    }

    /**
     * 配置Filter过滤器
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置SecuritManager
        filterFactoryBean.setSecurityManager(securityManager());
        //用户未登录时跳转的请求路径
        filterFactoryBean.setLoginUrl(SysRoute.REDIRECT_LOGIN);
        //用户未登录成功跳转的请求路径
        filterFactoryBean.setSuccessUrl("/");
        //用户没有访问权限时跳转的请求路径
        filterFactoryBean.setUnauthorizedUrl("/401");
        Map<String, Filter> filters = new LinkedHashMap();
        //配置拦截器,实现无权限返回(过滤器制定)
        filters.put("authc", new MyFormAuthenticationFilter());
        filters.put("roles", new MyRolesAuthorizationFilter());
        filterFactoryBean.setFilters(filters);
        Map<String, String> filterChainDefinitionMap = shiroFreshService.loadFilterChainDefinitionMap();
        filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return filterFactoryBean;
    }

}

realm

@Slf4j
public class SysUserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private EmpService empService;

    @Autowired
    private ConfigProperties configProperties;


    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        String username = (String) authenticationToken.getPrincipal();
        log.info("#SHIRO#认证" + username);
        SysUser sysUser = userService.getSysUserOneByUsername(username);
        if (ObjectUtils.isNotEmpty(sysUser)) {
            //status 用户状态,0,离职,1:正常,2:禁用
            switch (sysUser.status()) {
                case 0:
                    throw new UserStatusException(new ErrCode(10001, "用户离职状态,禁止登录"));
                case 2:
                    throw new UserStatusException(new ErrCode(10002, "用户锁定状态,禁止登录"));
                default:
                    break;
            }
            return new SimpleAuthenticationInfo(username, sysUser.password(), ByteSource.Util.bytes(username), getName());
        }
        throw new UnknownAccountException("用户名或密码不存在");
    }

    /**
     * 授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("#SHIRO#授权");
        if (principalCollection == null) {
            throw new AuthorizationException("用户凭证不能为空");
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        String username = (String) getAvailablePrincipal(principalCollection);
        //登录用户角色
        Set<String> roles = new HashSet<>();
        List<String> roleCodeList = empService.getRoleCodeListByUsername(username);
        if (CollectionUtils.isNotEmpty(roleCodeList)) {
            roles.addAll(roleCodeList.stream().map(String::toUpperCase).collect(Collectors.toSet()));
        }
        SysUser sysUser = userService.getSysUserOneByUsername(username);
        if (ObjectUtils.isNotEmpty(sysUser) && configProperties.getAdminId().equals(sysUser.id())) {
            roles.add(configProperties.getAdminRoleCode());
        }
        info.setRoles(roles);
        return info;
    }


    /**
     * 自定义方法:清除所有 授权缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }


}

MyFormAuthenticationFilter

/**
 * Name: 需要登录认证
 * Description:
 * User: bambo
 * Date: 2020-07-16
 * Time: 16:12
 */
@Slf4j
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {


    /**
     * @param request
     * @param response
     * @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
     * @throws IOException
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        log.info("#SHIRO#认证处理(1),onAccessDenied:MyFormAuthenticationFilter");
        Subject subject = this.getSubject(request, response);
        if (subject.getPrincipal() == null) {
            log.info("#SHIRO#认证处理(2-1),凭证丢失【重新登录】:MyFormAuthenticationFilter");
            if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {
                response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);
                response.setContentType(AjaxBoolUtil.CONTENT_TYPE);
                response.getWriter().write(GsonUtil.toString(Result.right("请重新登录!")));
            } else {
                ((HttpServletResponse) response).sendRedirect(SysRoute.LOGIN_LOGIN);
            }
        } else {
            log.info("#SHIRO#认证处理(2-2),未经认证【401】:MyFormAuthenticationFilter");
            if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {
                response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);
                response.setContentType(AjaxBoolUtil.CONTENT_TYPE);
                response.getWriter().write(GsonUtil.toString(Result.right("未经认证!")));
            } else {
                WebUtils.toHttp(response).sendError(401);
            }
        }
        return false;
    }


}

MyRolesAuthorizationFilter

@Slf4j
public class MyRolesAuthorizationFilter extends AuthorizationFilter {

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws IOException {
        log.info("#SHIRO#授权效验(1):MyRolesAuthorizationFilter");
        final Subject subject = getSubject(request, response);
        if (subject.getPrincipal() == null) {
            return false;
        }
        final String[] rolesArray = (String[]) mappedValue;
        if (rolesArray == null || rolesArray.length == 0) {
            log.info("#SHIRO#(2-1),无指定角色时,无需检查,允许访问:MyRolesAuthorizationFilter");
            return true;
        }
        for (String roleName : rolesArray) {
            if (subject.hasRole(roleName)) {
                log.info("#SHIRO#(2-2),有匹配角色,允许访问:MyRolesAuthorizationFilter");
                return true;
            }
        }
        log.info("#SHIRO#未经授权(3),无授权:MyRolesAuthorizationFilter");
        return false;
    }


    @Override
    public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        log.info("#SHIRO#授权处理(1),onAccessDenied:MyRolesAuthorizationFilter");
        Subject subject = this.getSubject(request, response);
        if (subject.getPrincipal() == null) {
            log.info("#SHIRO#授权处理(2-1),凭证丢失【重新登录】:MyRolesAuthorizationFilter");
            if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {
                response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);
                response.setContentType(AjaxBoolUtil.CONTENT_TYPE);
                response.getWriter().write(GsonUtil.toString(Result.right("请重新登录!")));
            } else {
                ((HttpServletResponse) response).sendRedirect(SysRoute.LOGIN_LOGIN);
            }
        } else {
            log.info("#SHIRO#授权处理(2-2),未经授权【403】:MyRolesAuthorizationFilter");
            if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {
                response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);
                response.setContentType(AjaxBoolUtil.CONTENT_TYPE);
                response.getWriter().write(GsonUtil.toString(Result.right("未经授权!")));
            } else {
                WebUtils.toHttp(response).sendError(403);
            }
        }
        return false;
    }
}

Sha256PasswordHelper

public class Sha256PasswordHelper {

    public static String encryption(String username, String pwd) {
        return new Sha256Hash(pwd, username, 1024).toString();
    }
}

ShiroBeanLifecycleConfig

@Configuration
public class ShiroBeanLifecycleConfig {

    /**
     * 安全框架shiro的bean生命周期
     * LifecycleBeanPostProcessor将Initializable和Destroyable的实现类统一在其内部自动分别调用了Initializable.init()和Destroyable.destroy()方法,
     * 从而达到管理shiro bean生命周期的目的。
     *
     * @return
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * APC 自动代理创建器
     * 扫描上下文,寻找所有的Advistor(通知器),将这些Advisor应用到所有符合切入点的Bean中。所以必须在lifecycleBeanPostProcessor创建之后创建。
     *
     * @return
     * @DependsOn({"lifecycleBeanPostProcessor"}) 保证创建DefaultAdvisorAutoProxyCreator 之前先创建LifecycleBeanPostProcessor 。
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        //使用cglib方式为Action对象创建代理对象[pom.xml如果引入了aop-starter依赖包装,就需要做出更改]
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
}

ToolDateUtil

@Slf4j
public class ToolDateUtil {


    //LocalDate -> Date
    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    //LocalDateTime -> Date
    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    //String -> Date
    public static Date asYMDDate(String date) {
        DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return fmt.parse(date);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    //Date -> LocalDate
    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    //Date -> LocalDateTime
    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    //Date -> String
    public static String YmdHmToString(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
        return formatter.format(date);
    }

    //Date -> String
    public static String YmdToString(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        return formatter.format(date);
    }

    //String -> Date
    public static Date asMinDate(String ymd) {
        DateTimeFormatter dtfYMD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date = LocalDate.parse(ymd, dtfYMD);
        return asDate(LocalDateTime.of(date, LocalTime.MIN));
    }

    //String -> Date
    public static Date asMaxDate(String ymd) {
        DateTimeFormatter dtfYMD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date = LocalDate.parse(ymd, dtfYMD);
        return asDate(LocalDateTime.of(date, LocalTime.MAX));
    }

}

调用

 @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;
    shiroFreshService..reCreateFilterChains(shiroFilterFactoryBean)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值