zoukankan      html  css  js  c++  java
  • shiro笔记(三)

    起初刚接触到授权这个词我以为是将某个权限授予某个用户,后来经过网络调研发现,授权实际上是检验某个用户是否有访问某个资源的权限。

    比如,普通用户想观看VIP视频会被网站阻止,因为该用户没有访问该资源的权限。

    关于授权需要了解的概念:

    主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)

    主体:在shiro中代表用户,不一定是某个人,也许是爬虫。

    资源:用户可以访问的东西。

    权限:代表的是用户有没有某些操作(crud之类的)的权限。

    角色:用户的角色,权限的集合。

    粗粒度:以角色来授权。

    细粒度:以权限来授权。

    如果采用粗粒度的方式,当某个角色不再具备某个权限时,需要改动代码。


    授权的三种方式:

    代码授权、JSP标签授权(这个就不学了)、注解授权(这个着重看一下)。

    代码授权:

    Subject subject = SecurityUtils.getSubject();  
    if(subject.hasRole(“角色”)) {  
        //有权限  
    } else {  
        //无权限  
    }  

    注解授权:

    @RequiresRoles("角色")  
    public void check() {  
        //有权限  
    } 

    教程里关于这部分的代码貌似没给太多...于是,我自己发挥了一下...

    首先,是代码授权,自定义realm,假装是从数据源中获取数据...

    public class SelfRealm extends AuthorizingRealm {
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //授权会调用这个方法,从数据源中获取权限列表
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRole("admin"); //假装从数据源中获取的用户权限为admin
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //认证方法,和上一篇笔记的一样
            String username = (String) authenticationToken.getPrincipal();
            String password = new String((char[])authenticationToken.getCredentials());
            if(!"joker".equals(username)) {
                throw new UnknownAccountException();
            }
            if(!"shiro".equals(password)) {
                throw new IncorrectCredentialsException();
            }
            return new SimpleAuthenticationInfo(username, password, getName());
        }
    }

    然后,修改了一下测试方法,假装用户登录后访问某个资源,然后进行判断(采用的方式是粗粒度)

    public class Boot {
    
        @Test
        public void test() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(new SelfRealm());
            SecurityUtils.setSecurityManager(securityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("joker", "shiro");
            try {
                subject.login(token);
            } catch (Exception e) {}
            System.out.println("登录状态:" + subject.isAuthenticated());
            System.out.println("是否为管理员:" + subject.hasRole("admin")); //此处假装访问某资源,进行校验
        }
    }

    经测试发现,如果用户不登录,则授权结果一定为false,如果用户登录后登出,那么结果也是false。

    授权流程:

    主体(Subject)调用isPermitted(是否拥有某权限,细粒度)/hasRole(是否拥有某角色,粗粒度),会调用到(核心管理器)SecurityManager,然后会调用到授权器(Authorizer)。

    后面还有一些流程,感觉记不太住,此处暂不做记录,等以后有能力阅读shiro源码再详细学习。

    教程中介绍了两种授权的流程:

    授权器授权、realm授权(没太搞懂怎么弄...)

    还有一些高端操作,自定义授权器什么的...估计以后有能力读懂源码,就可以领会这些进阶操作,现阶段暂时略过。

    目前没整合其他框架搭建一个小的项目,没想到用什么简单的方式测试注解方式授权,只好拿着上次根据网上教程搭建的练手shiro整合springboot项目改造了一下。

       @GetMapping("/role")
        @RequiresRoles("admin")
        public String role() {
            return "role success";
        }

    然后惊讶地发现这个注解压根不生效,但是,如果采用代码授权的话还是可以正确执行。

    于是,再一次面向网络编程,发现搜到一堆xml之类的配置,嗯... ...但是我需要的是配置类的方式进行配置,终于找到一篇文章说需要加入一个Bean。

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
            return new DefaultAdvisorAutoProxyCreator();
    }

    加入之后发现还是不生效... ...

    无奈之下,看了一波xml配置,发现其中用到了AuthorizationAttributeSourceAdvisor,并且将securityManager交给了这个类的实例对象。

    于是,又加入了一段代码:

       @Bean
        public static AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }

    这一次注解终于生效了,之前看到一篇文章说这个注解必须写在service层才行,写在controller层不管用,经实践表明写在controller层是管用的,并且还有一个意外发现,当controller和service两层都有这个注解时,

    如果controller层通过授权,则即便service层也会通过,即便该用户并不具备service层注解要求的权限也一样会通过。

    以下是我根据网上的文章配置的简易版shiro配置类(记录一下,省得下次再去查):

    @Configuration
    public class ShiroConfig {
    
        @Bean
        public BlogRealm newBlogRealm() {
            return new BlogRealm();
        }
    
        @Bean
        public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
            return new DefaultAdvisorAutoProxyCreator();
        }
    
        @Bean
        public static AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
        @Bean("securityManager")
        public SecurityManager newSecurityManager(){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(newBlogRealm());
            return securityManager;
        }
    
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            Map<String, String> map = new HashMap<>();
            map.put("/blog/login", "anon");//登录这一行和下一行应该配置一个即可(个人猜测,暂未实践)
            shiroFilterFactoryBean.setLoginUrl("/blog/login");
            map.put("/blog/role", "authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
            return shiroFilterFactoryBean;
        }
    }
  • 相关阅读:
    创建异步Web服务
    MCAD考试计划
    微软面试题
    Reborn
    Qt项目注意事项
    在ASP.Net中两种利用CSS实现多界面
    为ASP.NET控件添加常用的JavaScript操作
    用Split函数分隔字符串
    Microsoft .NET Pet Shop 4.0
    搞定QString,string,char*,CString的互转
  • 原文地址:https://www.cnblogs.com/wxdmw/p/13897651.html
Copyright © 2011-2022 走看看