最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring-boot結合Shrio實現(xiàn)JWT的方法

 更新時間:2018年05月07日 08:34:39   作者:workabee  
這篇文章主要介紹了Spring-boot結合Shrio實現(xiàn)JWT的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文介紹了Spring-boot結合Shrio實現(xiàn)JWT的方法,分享給大家,具體如下:

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

  1. 用戶登錄時的驗證;
  2. 用戶登錄后每次訪問時的權限認證

主要解決方法:使用自定義的Shiro Filter

項目搭建:

這是一個spring-boot 的web項目,不了解spring-boot的項目搭建,請google。

pom.mx引入相關jar包

 <!-- shiro 權限管理 -->
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>${shiro.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>${shiro.version}</version>
  </dependency>
 <!-- JWT -->
   <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
  </dependency>

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<String, Filter> filterMap = new HashMap<>();
    filterMap.put("JWTFilter", new JWTFilter());
    shiroFilterFactoryBean.setFilters(filterMap);
    /*
     * 自定義url規(guī)則
     * http://shiro.apache.org/web.html#urls-
     */
    Map<String, String> 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

執(zhí)行順序:preHandle -> doFilterInternal -> executeLogin -> onLoginSuccess

主要判斷是不是登錄請求的是 doFilterInternal

public class JWTFilter extends BasicHttpAuthenticationFilter {
  /**
   * 自定義執(zhí)行登錄的方法
   */
  @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);
    //錯誤拋出異常
  }

  /**
   * 最先執(zhí)行的方法
   */
  @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")) {
      //執(zhí)行登錄
      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();
          //塞入容器,統(tǒng)一調用
          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內發(fā)生的異常,@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中實現(xiàn)緩存。我認為也是不錯的。

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Java數(shù)據(jù)結構和算法之鏈表詳解

    Java數(shù)據(jù)結構和算法之鏈表詳解

    鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結構,java代碼實現(xiàn)單鏈表,插入,刪除和遍歷等功能,這篇文章主要給大家介紹了關于Java數(shù)據(jù)結構和算法之鏈表的相關資料,需要的朋友可以參考下
    2024-01-01
  • 使用springboot的jar包能夠以service方式啟動

    使用springboot的jar包能夠以service方式啟動

    這篇文章主要介紹了使用springboot的jar包能夠以service方式啟動,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot策略模式的實踐使用

    SpringBoot策略模式的實踐使用

    這篇文章主要介紹了SpringBoot 策略模式的實踐使用,幫助大家更好的理解和學習使用SpringBoot,感興趣的朋友可以了解下
    2021-04-04
  • ConcurrentHashMap是如何保證線程安全

    ConcurrentHashMap是如何保證線程安全

    大家好,本篇文章主要講的是ConcurrentHashMap是如何保證線程安全,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • Java 自定義Spring框架與Spring IoC相關接口分析

    Java 自定義Spring框架與Spring IoC相關接口分析

    Spring框架是由于軟件開發(fā)的復雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限于服務器端的開發(fā)
    2021-10-10
  • JAVA基礎之注解與反射的使用方法和場景

    JAVA基礎之注解與反射的使用方法和場景

    這篇文章主要給大家介紹了關于JAVA基礎之注解與反射的使用方法和場景的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Spring Boot熱加載jar實現(xiàn)動態(tài)插件的思路

    Spring Boot熱加載jar實現(xiàn)動態(tài)插件的思路

    本文主要介紹在 Spring Boot 工程中熱加載 jar 包并注冊成為 Bean 對象的一種實現(xiàn)思路,在動態(tài)擴展功能的同時支持在插件中注入主程序的 Bean 實現(xiàn)功能更強大的插件
    2021-10-10
  • Java Lambda表達式與引用類淺析

    Java Lambda表達式與引用類淺析

    Lambda表達式是Java SE8中一個重要的新特性,允許通過表達式來代替功能接口。本文將通過一些簡單的示例和大家講講Lamda表達式的使用,感興趣的可以了解一下
    2023-01-01
  • 關于Spring中的@Configuration中的proxyBeanMethods屬性

    關于Spring中的@Configuration中的proxyBeanMethods屬性

    這篇文章主要介紹了關于Spring中的@Configuration中的proxyBeanMethods屬性,需要的朋友可以參考下
    2023-07-07
  • Java Web實現(xiàn)文件上傳和下載接口功能詳解

    Java Web實現(xiàn)文件上傳和下載接口功能詳解

    這篇文章主要為大家詳細介紹了Java Web實現(xiàn)文件上傳和下載接口功能的相關知識,文中的示例代碼講解詳細,對我們學習有一定的借鑒價值,需要的可以參考一下
    2022-12-12

最新評論

增城市| 铜川市| 体育| 棋牌| 雅江县| 平顶山市| 齐齐哈尔市| 上犹县| 故城县| 句容市| 陆河县| 广河县| 辉南县| 黄山市| 新建县| 宜昌市| 偃师市| 清远市| 阿尔山市| 确山县| 怀化市| 罗定市| 理塘县| 株洲县| 阿坝县| 周口市| 林口县| 海门市| 阿鲁科尔沁旗| 城步| 花莲县| 康马县| 临高县| 永顺县| 山阳县| 呼伦贝尔市| 贵南县| 毕节市| 诸暨市| 东海县| 宁阳县|