Spring Boot+Shro+JWTがマルチRealmを実現した時Filter異常捕捉

10248 ワード

最近、おじさんは会社の需要を受けて、前後の端の分離のバックグランドの管理モジュールのインターフェイスを構築します.登録モジュールに関する要求を簡単に説明する:
  • ユーザがユーザ名とパスワードを入力してJWT Tokenトークン
  • を取得する.
  • ユーザは、JWT Tokenトークンを使用してバックエンドサービスインターフェース
  • にアクセスする.
    おじさんが簡単にSprigbootを集めてShroにする過程を言います.1.pom.xmlにShroを導入します.
    
    
        org.apache.shiro
        shiro-spring
    
    
    2.自分のRealmを書く:UserRealm.java、JWTRRealm.java、
    /**
    *     UserRealm          AuthenticatingRealm   
    **/
    public class UserRealm extends AuthenticatingRealm {
         /**
         *        Realm            Realm
         */ 
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof UsernamePasswordToken;
        } 
        /**
        *              
        **/
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //TODO                
         }
    }
    
    /**
    *   JWTRealm      ,       ,    AuthorizingRealm 
    **/
    public class JWTRealm extends AuthorizingRealm {
        /**
        *         Realm            Realm
        **/
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof JwtToken;
        }
        
        /**
        *                 
        **/ 
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //TODO           
        }
        /**
        *        JWTToken  
        **/
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
            //TODO              
        }
    }
    
    
    3.JWT Filter.javaを書く
    public class JwtFilter extends BasicHttpAuthenticationFilter {
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            //TODO
            return true;
        }
        
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            //TODO 
            return false;
        }
        
    }
    
    4.ShroConfig.javaを書く
    /**
    *         
    **/
    @Configuration
    public class ShiroConfig {
        /**
         *   shiro Filter,    
         */
        @Bean
        public FilterRegistrationBean filterRegistrationBean(DefaultWebSecurityManager securityManager)
                throws Exception {
            FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
            filterRegistration.setFilter((Filter) shiroFilter(securityManager).getObject());
            filterRegistration.addInitParameter("targetFilterLifecycle", "true");
            filterRegistration.setAsyncSupported(true);
            filterRegistration.setEnabled(true);
            filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
            return filterRegistration;
        }
    
        @Bean
        public DefaultWebSecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //   realm,          
            // One or more realms must be present to execute an authentication attempt. One
            // or more realms must be present to execute an authentication attempt.
            securityManager.setAuthenticator(authenticator());
            securityManager.setAuthorizer(authorizer());
            return securityManager;
        }
        
        /**
        *              realm
        */
        @Bean("userRealm")
        public Realm userRealm() {
            UserRealm userRealm = new UserRealm();
            return userRealm;
        }
    
        /**
        *   JWT token   realm
        */
        @Bean("jwtRealm")
        public Realm jwtRealm() {
            JWTRealm jwtRealm= new JWTRealm();
            return jwtRealm;
        }
         /**
         *    Authenticator         
         */
        @Bean
        public Authenticator authenticator() {
            ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();//      
            //     Realm,          ;    jwt token          
            authenticator.setRealms(Arrays.asList(jwtRealm(), userRealm()));
            //     realm    ,          
            authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
            return authenticator;
        }
        
        /**
         *    authorizer         
         * @return
         */
        @Bean
        public Authorizer authorizer() {
            ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();//   
            authorizer.setRealms(Arrays.asList(jwtShiroRealm()));
            return authorizer;
        }
        
        /**
        *   session,          。           。
        *       ,         Subject.getSession()     session,       ,      noSessionCreation Filter   
        */
        @Bean
        protected SessionStorageEvaluator sessionStorageEvaluator() {
            DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
            sessionStorageEvaluator.setSessionStorageEnabled(false);
            return sessionStorageEvaluator;
        }
        
        /**
         *      ,     Filter  
         */
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
            ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
            factoryBean.setSecurityManager(securityManager);
            //      
            Map filterMap = new HashMap();
            // JWT   
            filterMap.put("jwtFilter", jwtFilter());// JwTfilter
            factoryBean.setFilters(filterMap);
            //    
            factoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap()); 
            return factoryBean;
        }
    
        @Bean
        protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
            DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); 
            chainDefinition.addPathDefinition("/login", "noSessionCreation,anon"); // login    ,noSessionCreation         session     
            chainDefinition.addPathDefinition("/**", "noSessionCreation,jwtFilter"); //         
            return chainDefinition;
        }
    
        //    @Bean  ,  spring      filter,         
        protected JwtFilter jwtFilter() {
            return new JwtFilter();
        }
        /**
        *   Shiro     
        */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
                @Qualifier("securityManager") SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }
    }
    
    はい、ここに来たら、私達はシンロの集積作業を完成したと見なしてもいいです.
    テストコードを任意に書きます.
    @RestController
    public class TestController {
        @GetMapping("/helloWorld")
        @RequiresPermissions("system:test:hello")
        public String helloWorld() {
            return “hello world";
        }
    }
    
    プロジェクトを起動して、このインターフェースをお願いします.
    マルチRealmの登録が実現された後、JWT Realmのアイデンティティ検証エラーが発生した場合、JWT Filterで取得した異常タイプはAuthentication Exceptionであり、JWTRU Realmでは異なる異常に応じて処理ができなくなることが分かりました.どうすればいいですかトレース異常スローフローがマルチRealmを発見した場合、異常はModularRealm Authenticatorで処理され、Authentication Exceptionを一括してスローします.ですから、おじさんがModularRealm AuthenticatorのdoMultiRealmAuthenticationの書き換え方法を見つけたらいいです.
    public class MultiRealmAuthenticator extends ModularRealmAuthenticator {
        private static final Logger log = LoggerFactory.getLogger(MultiRealmAuthenticator.class);
        @Override
        protected AuthenticationInfo doMultiRealmAuthentication(Collection realms, AuthenticationToken token)
                throws AuthenticationException {
            AuthenticationStrategy strategy = getAuthenticationStrategy();
            AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
            if (log.isTraceEnabled()) {
                log.trace("Iterating through {} realms for PAM authentication", realms.size());
            }
            AuthenticationException authenticationException = null;
            for (Realm realm : realms) {
                aggregate = strategy.beforeAttempt(realm, token, aggregate);
                if (realm.supports(token)) {
                    log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
                    AuthenticationInfo info = null;
                    try {
                        info = realm.getAuthenticationInfo(token);
                    } catch (AuthenticationException e) {
                        authenticationException = e;
                        if (log.isDebugEnabled()) {
                            String msg = "Realm [" + realm
                                    + "] threw an exception during a multi-realm authentication attempt:";
                            log.debug(msg, e);
                        }
                    }
                    aggregate = strategy.afterAttempt(realm, token, info, aggregate, authenticationException);
                } else {
                    log.debug("Realm [{}] does not support token {}.  Skipping realm.", realm, token);
                }
            }
            if (authenticationException != null) {
                throw authenticationException;
            }
            aggregate = strategy.afterAllAttempts(token, aggregate);
            return aggregate;
        }
    }
    
    書き換えた後、ShroConfig.javaの身分認証を置き換えればいいです.
            /**
         *    Authenticator         
         */
        @Bean
        public Authenticator authenticator() {
            MultiRealmAuthenticator authenticator = new MultiRealmAuthenticator();
            //     Realm,                 ;    jwt token   
            authenticator.setRealms(Arrays.asList(jwtShiroRealm(), dbShiroRealm()));
            //     realm    ,          
            authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
            return authenticator;
        }
    
    穴が多くても、怖くない、起きても、穴に落ちるとおっさんが言いました.