国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring-boot、Shrio實現JWT

qylost / 3345人閱讀

摘要:截獲頁面錯誤處理邏輯關于權限等授權信息,可以直接放到中實現緩存。我認為也是不錯的。源碼奉上分支溫馨提示平時測試代碼可能比較亂。如果更好的實現,讓我學習,讓我我進步,請聯系我。

關于驗證大致分為兩個方面:

用戶登錄時的驗證;

用戶登錄后每次訪問時的權限認證

主要解決方法:使用自定義的Shiro Filter 項目搭建:
這是一個spring-boot 的web項目,不了解spring-boot的項目搭建,請google。

pom.mx引入相關jar

 
    
        org.apache.shiro
        shiro-spring
        ${shiro.version}
    
    
        org.apache.shiro
        shiro-core
        ${shiro.version}
    
 
     
        io.jsonwebtoken
        jjwt
        0.9.0
    

Shrio 的相關配置

劃重點!!自定義了一個Filter

filterMap.put("JWTFilter", new JWTFilter());

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 添加自己的過濾器并且取名為JWTFilter
        Map filterMap = new HashMap<>();
        filterMap.put("JWTFilter", new JWTFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        /*
         * 自定義url規則
         * http://shiro.apache.org/web.html#urls-
         */
        Map filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        filterChainDefinitionMap.put("/**", "JWTFilter");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    /**
     * securityManager 不用直接注入shiroDBRealm,可能會導致事務失效
     * 解決方法見 handleContextRefresh
     * http://www.debugrun.com/a/NKS9EJQ.html
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(TokenRealm tokenRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(tokenRealm);
        /*
         * 關閉shiro自帶的session,詳情見文檔
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);
        return manager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean(name = "TokenRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public TokenRealm tokenRealm() {
        return new TokenRealm();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 強制使用cglib,防止重復代理和可能引起代理出錯的問題
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

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

自定義Shrio filter

執行順序:preHandle -> doFilterInternal -> executeLogin -> onLoginSuccess
主要判斷是不是登錄請求的是 doFilterInternal

public class JWTFilter extends BasicHttpAuthenticationFilter {

    /**
     * 自定義執行登錄的方法
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        UsernamePasswordToken usernamePasswordToken = JSON.parseObject(httpServletRequest.getInputStream(), UsernamePasswordToken.class);
        // 提交給realm進行登入,如果錯誤他會拋出異常并被捕獲
        Subject subject = this.getSubject(request, response);
        subject.login(usernamePasswordToken);
        return this.onLoginSuccess(usernamePasswordToken, subject, request, response);
        //錯誤拋出異常
    }

    /**
     * 最先執行的方法
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        return super.preHandle(request, response);
    }

    /**
     * 登錄成功后登錄的操作
     * 加上jwt 的header
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String jwtToken = Jwts.builder()
                .setId(token.getPrincipal().toString())
                .setExpiration(DateTime.now().plusMinutes(30).toDate())
                .signWith(SignatureAlgorithm.HS256, JWTCost.signatureKey)
                .compact();
        httpServletResponse.addHeader(AUTHORIZATION_HEADER, jwtToken);
        return true;
    }

    /**
     * 登錄以及校驗的主要流程
     * 判斷是否是登錄,或者是登陸后普通的一次請求
     */
    @Override
    public void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        String servletPath = httpServletRequest.getServletPath();
        if (StringUtils.equals(servletPath, "/login")) {
            //執行登錄
            this.executeLogin(servletRequest, servletResponse);
        } else {
            String authenticationHeader = httpServletRequest.getHeader(AUTHORIZATION_HEADER);
            if (StringUtils.isNotEmpty(authenticationHeader)) {

                Claims body = Jwts.parser()
                        .setSigningKey(JWTCost.signatureKey)
                        .parseClaimsJws(authenticationHeader)
                        .getBody();
                if (body != null) {
                    //更新token
                    body.setExpiration(DateTime.now().plusMinutes(30).toDate());
                    String updateToken = Jwts.builder().setClaims(body).compact();
                    httpServletResponse.addHeader(AUTHORIZATION_HEADER, updateToken);

                    //添加用戶憑證
                    PrincipalCollection principals = new SimplePrincipalCollection(body.getId(), JWTCost.UserNamePasswordRealm);//拼裝shiro用戶信息
                    WebSubject.Builder builder = new WebSubject.Builder(servletRequest, servletResponse);
                    builder.principals(principals);
                    builder.authenticated(true);
                    builder.sessionCreationEnabled(false);
                    WebSubject subject = builder.buildWebSubject();
                    //塞入容器,統一調用
                    ThreadContext.bind(subject);
                    filterChain.doFilter(httpServletRequest, httpServletResponse);
                }
            } else {
                httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
            }
        }
    }
}

登錄失敗處理

處理Shrio異常
@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public Object allExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        String message = exception.getCause().getMessage();
        LogUtil.error(message);
        return new ResultInfo(exception.getClass().getName(), message);
    }

    /*=========== Shiro 異常攔截==============*/

    @ExceptionHandler(value = IncorrectCredentialsException.class)
    public String IncorrectCredentialsException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "IncorrectCredentialsException";
    }

    @ExceptionHandler(value = UnknownAccountException.class)
    public String UnknownAccountException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "UnknownAccountException";
    }

    @ExceptionHandler(value = LockedAccountException.class)
    public String LockedAccountException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "LockedAccountException";
    }

    @ExceptionHandler(value = ExcessiveAttemptsException.class)
    public String ExcessiveAttemptsException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "ExcessiveAttemptsException";
    }

    @ExceptionHandler(value = AuthenticationException.class)
    public String AuthenticationException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "AuthenticationException";
    }

    @ExceptionHandler(value = UnauthorizedException.class)
    public String UnauthorizedException(HttpServletRequest request, HttpServletResponse response, Exception exception) {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        return "UnauthorizedException";
    }
}
處理JWT異常 這是個坑,因為是在filter內發生的異常,@ExceptionHandler是截獲不到的。
/**
 * 截獲spring boot Error頁面
 */
@RestController
public class GlobalExceptionHandler implements ErrorController {
    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping(value = "/error")
    public Object error(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 錯誤處理邏輯
        Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
        Throwable cause = exception.getCause();
        if (cause instanceof ExpiredJwtException) {
            response.setStatus(HttpStatus.GATEWAY_TIMEOUT.value());
            return new ResultInfo("ExpiredJwtException", cause.getMessage());
        }
        if (cause instanceof MalformedJwtException) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return new ResultInfo("MalformedJwtException", cause.getMessage());
        }
        return new ResultInfo(cause.getCause().getMessage(), cause.getMessage());
    }
}
關于權限等授權信息,可以直接放到Redis中實現緩存。我認為也是不錯的。

源碼奉上:githup-shiro分支 :溫馨提示:平時測試代碼可能比較亂。

如果更好的實現,讓我學習,讓我我進步,請聯系我。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69300.html

相關文章

  • 使用JWT保護你的Spring Boot應用 - Spring Security實戰

    摘要:創建應用有很多方法去創建項目,官方也推薦用在線項目創建工具可以方便選擇你要用的組件,命令行工具當然也可以。對于開發人員最大的好處在于可以對應用進行自動配置。 使用JWT保護你的Spring Boot應用 - Spring Security實戰 作者 freewolf 原創文章轉載請標明出處 關鍵詞 Spring Boot、OAuth 2.0、JWT、Spring Security、SS...

    wemall 評論0 收藏0
  • 高性能配置管理中心 duic

    摘要:配置中心在軟件開發中隨著業務的需要需求的變更程序的靈活我們時常需要在項目中設置各種開關或者配置項在往常時一般會采用配置文件的方式但是在這分布式集群時代采用傳統的配置管理方式顯得有點力不從心同時在我們的終端我們也時常需要各種配置在面對大量的終 ______ _ ______ |_ _ `. (_) . ___ | | | `...

    binaryTree 評論0 收藏0
  • 高性能配置管理中心 duic

    摘要:配置中心在軟件開發中隨著業務的需要需求的變更程序的靈活我們時常需要在項目中設置各種開關或者配置項在往常時一般會采用配置文件的方式但是在這分布式集群時代采用傳統的配置管理方式顯得有點力不從心同時在我們的終端我們也時常需要各種配置在面對大量的終 ______ _ ______ |_ _ `. (_) . ___ | | | `...

    newsning 評論0 收藏0
  • SpringBoot 入門簡介

    摘要:這里使用的是數據庫啟動類上加上注解在啟動類中添加對包掃描掃描多個包下的可以有以下幾種方法掃描會自動加載相關配置,數據源就會自動注入到中,會自動注入到中,可以直接使用。有配置文件下的使用掃描多個包下的可以有以下幾種方法掃描 Spring-Boot 學習筆記 1 Spring-Boot 介紹 1.1 什么是Spring-Boot Spring-Boot是由Pivotal團隊提供的全新框架...

    chuyao 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<