zoukankan      html  css  js  c++  java
  • shiro1

    1.Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等.

    2.Authentication(认证)身份认证/登录,验证用户是不是拥有相应的身份,例如账号密码登陆;

    3.Authorization(授权)授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

    4.Session Manager(会话管理)会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

    5.Cryptography(加密)加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

    6.Web SupportWeb支持,可以非常容易的集成到Web环境;

    7.Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

    8.Concurrencyshiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

    9.Testing提供测试支持;

    10.Run As允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

    11.Remember Me记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

    注意:Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

    12.shiro外部架构

     应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:

    Subject主体,应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject , 代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

    SecurityManager安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

    Realm域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

    也就是说shiro从根本上讲就是:

    也就是说对于我们而言,最简单的一个Shiro应用:

    1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

    2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断

    从上面的一些内容也可以很容易的看到Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。

    13.shiro内部结构

     Subject主体,可以看到主体可以是任何可以与应用交互的“用户”;

    SecurityManager相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。

    Authenticator认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;(自定义认证策略)

    Authrizer授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

    Realm可以有1个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供

    注意:Shiro不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm;

    SessionManager如果写过Servlet就应该知道Session的概念,Session呢需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所有呢,Shiro就抽象了一个自己的Session来管理主体与应用之间交互的数据;这样的话,比如我们在Web环境用,刚开始是一台Web服务器;接着又上了台EJB服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到Memcached服务器);

    SessionDAODAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能;

    CacheManager缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

    Cryptography密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。

    14.过滤器

    当 Shiro 被运用到 web 项目时,Shiro 会自动创建一些默认的过滤器对客户端请求进行过滤。比如身份验证、授权等 相关的。默认拦截器可以参考 org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举 拦截器:

    anon org.apache.shiro.web.filter.authc.AnonymousFilter
    authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
    authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
    perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
    port org.apache.shiro.web.filter.authz.PortFilter
    rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
    roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
    ssl org.apache.shiro.web.filter.authz.SslFilter
    user org.apache.shiro.web.filter.authc.UserFilter
    logout org.apache.shiro.web.filter.authc.LogoutFilter
    noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter

    /admins/**=anon # 表示该 uri 可以匿名访问

    /admins/**=auth # 表示该 uri 需要认证才能访问

    /admins/**=authcBasic # 表示该 uri 需要 httpBasic 认证

    /admins/**=perms[user:add:*] # 表示该 uri 需要认证用户拥有 user:add:* 权限才能访问

    /admins/**=port[8081] # 表示该 uri 需要使用 8081 端口

    /admins/**=rest[user] # 相当于 /admins/**=perms[user:method],其中,method 表示 get、post、delete 等

    /admins/**=roles[admin] # 表示该 uri 需要认证用户拥有 admin 角色才能访问

    /admins/**=ssl # 表示该 uri 需要使用 https 协议

    /admins/**=user # 表示该 uri 需要认证或通过记住我认证才能访问

    /logout=logout # 表示注销,可以当作固定配置

    注意:

    anon,authcBasic,auchc,user 是认证过滤器。

    perms,roles,ssl,rest,port 是授权过滤器。

    15.Shiro认证过程中可以用的异常

    Subject subject = SecurityUtils.getSubject();
    if(!subject.isAuthenticated()){
      UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName,password);
      usernamePasswordToken.setRememberMe(true);
      try{
         subject.login(usernamePasswordToken);
      }catch (UnknownAccountException e){
         System.out.print("账户不存在:"+e.getMessage());
      }catch (LockedAccountException e){
         System.out.print("账户被锁定:"+e.getMessage());
      }catch (IncorrectCredentialsException e){
         System.out.print("密码不匹配:"+e.getMessage());
      }
    }
    

     16.配置Realm及多Realm的认证策略

    /***
    * 配置Realm
    * */
    @Bean
    Realm userRealm() {
        TestRealm userRealm = new TestRealm();
        return userRealm;
    }
    /***
     * 测试realm
     * @return
     */
    @Bean
    Realm testRealm() {
        return new TestRealm();
    }
     
    /**
     * 多Realm认证策略
     * @return
     */
    @Bean
    Authenticator authenticator() {
        ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        //使用一个通过验证即可通过验证的方式
        modularRealmAuthenticator.setAuthenticationStrategy(atLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }
    /**
     * 多使用所有reaml均通过才算认证通过作为策略
     * @return
     */
    @Bean
    AuthenticationStrategy allSuccessfulStrategy() {
        AllSuccessfulStrategy allSuccessfulStrategy = new AllSuccessfulStrategy();
        return allSuccessfulStrategy;
    }
    /**
     * 多使用所有reaml一个通过就算认证通过作为策略
     * @return
     */
    @Bean
    AuthenticationStrategy atLeastOneSuccessfulStrategy() {
        AtLeastOneSuccessfulStrategy atLeastOneSuccessfulStrategy = new AtLeastOneSuccessfulStrategy();
        return atLeastOneSuccessfulStrategy;
    }
    

     17.配置Cache

    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManager(cacheManager());
        em.setCacheManagerConfigFile("classpath: ehcach.xml");
        return em;
    }
     
    @Bean("cacheManager2")
    CacheManager cacheManager(){
        return CacheManager.create();
    }
    

    18.配置securityManager

    /***
     * 配置securityManager
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置单个realm.
        securityManager.setRealm(userRealm());
        //设置多个realm 授权验证时 只要一个通过就可以
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm());
        realms.add(userRealm());
        securityManager.setRealms(realms);
        // 自定义缓存实现 使用redis
    //        if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
    //            securityManager.setCacheManager(rediscacheManager());
    //        } else {
            securityManager.setCacheManager(ehCacheManager());
        //}
        //securityManager.setSessionManager(sessionManager());
        //多Reaml的认证策略
        securityManager.setAuthenticator(authenticator());
        return securityManager;
    }
    

     19.配置shiroFilterFactoryBean 其实就是Filter的规则

    /***
     *  配置shiroFilterFactoryBean
     *  配置基本的过滤规则
     * @param securityManager
     * @return
     */
    @Bean
    ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //配置管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //配置登陆登陆成功页面登陆失败页面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        shiroFilterFactoryBean.setSuccessUrl("/index.html");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403.html");
        //配置基本的策略规则,那些可以直接访问  那些需要权限  按照顺序,先配置的起作用
        //支持Ant风格 
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login.html","anon");
        filterChainDefinitionMap.put("**/login/**","anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        filterChainDefinitionMap.put("/upload/**", "anon");
        filterChainDefinitionMap.put("/files/**", "anon");
        //配置注销的URL
        filterChainDefinitionMap.put("/logout", "logout");
        //
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
     
    

    20.身份认证代码流程

    1、首先调用 Subject.login(token) 进行登录,其会自动委托给 SecurityManager

    2、SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator (认证器)进行身份验证;

    3、Authenticator(认证器) 才是真正的身份验证者,Shiro API 中核心的身份 认证入口点,此处可以自定义插入自己的实现;

    4、Authenticator 可能会委托给相应的 AuthenticationStrategy(认证策略) 进 行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;

    5、Authenticator 会把相应的 token 传入 Realm,从 Realm 获取 身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处 可以配置多个Realm,将按照相应的顺序及策略进行访问。

    21.身份验证实例

     22.Realm的认证和授权

    public class TestRealm extends AuthorizingRealm {
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //关于JWT的考虑,密码登陆还是要的,但是要多个Reamle同时用,
            UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken;
            String username = usernamePasswordToken.getUsername();
            System.out.print("根据username查询yoghurt");
            if("none".equals(username)){
               throw new UnknownAccountException("用户不存在");
            }
            //认证的实体信息, 可以放对象,以后可以随时取出来用,  JSP标签也可以直接去这个对象
            Object principal = username;
            //数据库中获取的密码
            Object credentials = "1234567";
            //封装一个带数据的对象,Shiro会拿这个对象和传进来的Token的密码进行对比,验证是否登录成功
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, credentials, getName());
            return simpleAuthenticationInfo;
        }
        //这个方法是用来授权的
        //查询登陆人是否有权限时就查询这个  如果设置了缓存,只会查一次
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //这个里面取的就是登陆认证时SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());的第一个参数
            Object user = principalCollection.getPrimaryPrincipal();
            //将其转为自己的用户,在从数据库获取到这个用户的角色  权限
            //MenuService menuService = ApplicationContextRegister.getBean(MenuService.class);
            //这里只查询了权限
            //Set<String> perms = menuService.listPerms(userId);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //放进去即可
            //info.setStringPermissions(perms);
            return info;
        }
    }
    

     23.

    5.2 多Realm认证策略: AuthenticationStrategy

    • AuthenticationStrategy 接口的默认实现:

    • FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第 一个 Realm 身份验证成功的认证信息,其他的忽略;

    • AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和 FirstSuccessfulStrategy 不同,将返回所有Realm身份验证成功的认证信 息;

    • AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有 Realm身份验证成功的认证信息,如果有一个失败就失败了。 • ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy 策略

    代码使用权限的方式:

     权限的规则规定:

     

    6.3 JSP 的标签:

     

     

  • 相关阅读:
    spring cloud 和 阿里微服务spring cloud Alibaba
    为WPF中的ContentControl设置背景色
    java RSA 解密
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Hystrix 配置参数全解析
    spring cloud 2020 gateway 报错503
    Spring Boot 配置 Quartz 定时任务
    Mybatis 整合 ehcache缓存
    Springboot 整合阿里数据库连接池 druid
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
  • 原文地址:https://www.cnblogs.com/cainame/p/11490528.html
Copyright © 2011-2022 走看看