spring 整合shiro ,并实现动态url 配置

shiro 与Spring 结合

  • 数据库实现,参考RBAC角色权限控制的实现

  • maven 导入相关包

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.3.2</version>
        </dependency>
    
  • web.xml 配置

    shiroFilter org.springframework.web.filter.DelegatingFilterProxy shiroFilter /*
  • spring_shiro.xml

    <bean id="myRealm" class="com.nzs.listener.MyShiroRealm"/>
    <!-- 缓存管理 -->
    <bean id="mycacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
    
    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
        <property name="cacheManager" ref="mycacheManager"></property>
    </bean>
    
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
    
    <!-- Shiro过滤器 -->
    <!--<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">-->
    <bean id="shiroFilter" class="com.nzs.listener.ShiroPermissionFactory">
    
        <property name="manageUserService" ref="manageUserService"/>
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份认证失败,则跳转到登录页面的配置 -->
        <property name="loginUrl" value="/login.jsp"/>
        <!-- 登录成功跳转页面的配置 -->
        <property name="successUrl" value="/index"/>
        <!-- 权限认证失败,则跳转到指定页面 -->
        <property name="unauthorizedUrl" value="/norole.jsp"/>
        <!-- Shiro连接约束配置,即过滤链的定义 -->
        <property name="filterChainDefinitions">
            <value>
                /manageUser/login=anon
                <!--/** = authc-->
            </value>
        </property>
    </bean>
    
  • 自定义的realm

    public class MyShiroRealm extends AuthorizingRealm {
    static IManageUserService manageUserService;
    public static final String SESSION_USER_KEY = “temp”;

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    //可自定义实现内容
        SecurityUtils.getSubject().getSession()
     .getAttribute(OneballShiroRealm.SESSION_USER_KEY);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }
    
    /**
     * 认证回调函数,登录信息和用户验证信息验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        //判断 manageUserService 是否为空
        if (manageUserService == null) {
            manageUserService = (ManageUserService) ApplicationContextUtil.getBean("manageUserService");
        }
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String userName = token.getUsername();
        String passWord = String.valueOf(token.getPassword());
        ManageUser manageUser = manageUserService.login(userName, passWord);
    
        if (manageUser == null) {
            return null; // 异常处理,找不到数据
        }
    
        Subject subject =  SecurityUtils.getSubject();
    
        //shiro session
        Session session = SecurityUtils.getSubject().getSession();
        session.setTimeout(60 * 60 * 3 * 1000);
        session.setAttribute(OneballShiroRealm.SESSION_USER_KEY, manageUser);
    
        //当前 Realm 的 name
        String realmName = this.getName();
        //登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的.
        Object principal = authcToken.getPrincipal();
        return new SimpleAuthenticationInfo(principal, passWord, realmName);
    }
    
    
    public IManageUserService getManageUserService() {
        return manageUserService;
    }
    
    public void setManageUserService(IManageUserService manageUserService) {
        this.manageUserService = manageUserService;
    }
    

    }

  • 继承ShiroFilterFactoryBean,实现从数据库动态加载权限信息

    public class ShiroPermissionFactory extends ShiroFilterFactoryBean {

    private ManageUserService manageUserService;
    
    
    /**记录配置中的过滤链*/
    public static String definition="";
    
    
    /**
     * 初始化设置过滤链
     */
    @Override
    public void setFilterChainDefinitions(String definitions) {
    

    // String token = manageUserService.getAdminToken(0);

        //可从数据库读取后,添加至过滤链,参考此处已注释的代码
        definition = definitions;//记录配置的静态过滤链
    

    // List permissions = permissService.findAll();
    Map<String, String> otherChains = new HashMap<String,String>();
    // permissions.forEach(permiss->{
    // //perms.add(e)
    otherChains.put(“/discover/newstag”, “authc,roles[user,admin]”);
    // });
    //加载配置默认的过滤链
    Ini ini = new Ini();
    ini.load(definitions);
    Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
    if (CollectionUtils.isEmpty(section)) {
    section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
    }
    //加上数据库中过滤链
    section.putAll(otherChains);
    setFilterChainDefinitionMap(section);

    }
    
    public ManageUserService getManageUserService() {
        return manageUserService;
    }
    
    public void setManageUserService(ManageUserService manageUserService) {
        this.manageUserService = manageUserService;
    }
    

    }

  • FilterChainDefinitionsService实现,无需部署,重新加载权限

    @Service
    public class FilterChainDefinitionsService implements IFilterChainDefinitionsService {
    @Autowired
    private ShiroPermissionFactory permissFactory;

    @Override
    public void reloadFilterChains() {
        synchronized (permissFactory) {   //强制同步,控制线程安全
            AbstractShiroFilter shiroFilter = null;
    
            try {
                shiroFilter = (AbstractShiroFilter) permissFactory.getObject();
    
                PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter
                        .getFilterChainResolver();
                // 过滤管理器
                DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager();
                // 清除权限配置
                manager.getFilterChains().clear();
                permissFactory.getFilterChainDefinitionMap().clear();
                // 重新设置权限
                permissFactory.setFilterChainDefinitions(ShiroPermissionFactory.definition);//传入配置中的filterchains
    
                Map<String, String> chains = permissFactory.getFilterChainDefinitionMap();
                //重新生成过滤链
                if (!CollectionUtils.isEmpty(chains)) {
                    chains.forEach((url, definitionChains) -> {
                        manager.createChain(url, definitionChains.trim().replace(" ", ""));
                    });
                }
                // manager.addToChain("/discover/banner", "perms", "sssss");
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    }

  • 登录验证的实现

    //示例代码,未实现加密验证
    private String loginUser(ManageUser user) {
    // if (isRelogin(user)) {
    // // 如果已经登陆,无需重新登录
    // return “success”;
    // }
    return shiroLogin(user); // 调用shiro的登陆验证
    }

    private String shiroLogin(ManageUser user) {
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword().toCharArray(), null);
    

    // token.setRememberMe(true);
    // shiro登陆验证
    try {
    // System.out.println(SecurityUtils.getSubject());
    SecurityUtils.getSubject().login(token);
    } catch (UnknownAccountException ex) {
    return “用户不存在或者密码错误!”;
    } catch (IncorrectCredentialsException ex) {
    return “用户不存在或者密码错误!”;
    }catch (ExcessiveAttemptsException ex) {
    return “账号或密码错误次数过多,请稍后重试!”;
    } catch (AuthenticationException ex) {
    return ex.getMessage(); // 自定义报错信息
    } catch (Exception ex) {
    ex.printStackTrace();
    return “内部错误,请重试!”;
    }
    return “success”;
    }

    private boolean isRelogin(ManageUser user) {
        Subject us = SecurityUtils.getSubject();
        if (us.isAuthenticated()) {
            return true; // 参数未改变,无需重新登录,默认为已经登录成功
        }
        return false; // 需要重新登陆
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值