Spring Security + JWT實現先後端分離權限認證

 

如今國內先後端不少公司都在使用先後端分離的開發方式,雖然也有不少人並不贊同先後端分離,好比如下這篇博客就頗有意思:html

https://www.aliyun.com/jiaocheng/650661.html前端


咱們從技術角度來看的話:node

http://blog.jobbole.com/111624/
http://www.360doc.com/content/18/0511/06/36490684_752894279.shtmlweb

摘要:spring

爲何選擇先後端分離

  • 在之前傳統的網站開發中,前端通常扮演的只是切圖的工做,只是簡單地將UI設計師提供的原型圖實現成靜態的HTML頁面,而具體的頁面交互邏輯,好比與後臺的數據交互工做等,可能都是由後臺的開發人員來實現的,或者是前端是牢牢的耦合後臺。好比,之前淘寶的Web基本上都是基於MVC框架webx,架構決定了前端只能依賴後端。因此他們的開發模式依然是,前端寫好靜態demo,後端翻譯成VM模版,這種模式的問題就不說了,被吐槽了好久。
  • 並且更有可能後臺人員直接兼顧前端的工做,一邊實現API接口,一邊開發頁面,二者互相切換着作,並且根據不一樣的url動態拼接頁面,這也致使後臺的開發壓力大大增長。先後端工做分配不均。不只僅開發效率慢,並且代碼難以維護。而先後端分離的話,則能夠很好的解決先後端分工不均的問題,將更多的交互邏輯分配給前端來處理,然後端則能夠專一於其本職工做,好比提供API接口,進行權限控制以及進行運算工做。而前端開發人員則能夠利用nodejs來搭建本身的本地服務器,直接在本地開發,而後經過一些插件來將api請求轉發到後臺,這樣就能夠徹底模擬線上的場景,而且與後臺解耦。前端能夠獨立完成與用戶交互的整一個過程,二者均可以同時開工,不互相依賴,開發效率更快,並且分工比較均衡。

固然,站在個人角度,CTO要求咱們用先後端分離我就用好了,先後端分離的權限控制問題要稍微複雜一些,咱們最近的項目採用security+jwt的方式來實現先後端分離的權限控制。編程

Spring Security是一個可以爲基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組能夠在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,爲應用系統提供聲明式的安全訪問控制功能,減小了爲企業系統安全控制編寫大量重複代碼的工做。json

關於security的其餘知識能夠看:後端

http://www.javashuo.com/article/p-qyodtway-eg.htmlapi

Json web token (JWT),是爲了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標準((RFC 7519)。該標準被設計爲緊湊且安全的,通常被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也能夠增長一些額外的其它業務邏輯所必須的聲明信息。固然該標準也可直接被用於認證,也可被加密。安全

關於JWT能夠看下面這篇博客:

https://www.cnblogs.com/jiangwz/p/9503914.html

spring security + jwt的具體實現思路是:
用戶登錄後臺,後臺生成一個jwt簽名返回給前端,前端每次請求將簽名放在Header,後臺驗證簽名是否正確。

關於security的部分這裏再也不贅述

jwt

<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt</artifactId>
   <version>0.9.0</version>
</dependency>

驗證token

public class JwtAuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter { @Autowired private CustomerUserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; private String tokenHeader="Authorization"; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResopnse = (HttpServletResponse) response; if("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) { httpResopnse.setStatus(HttpServletResponse.SC_OK); } else { String authToken = httpRequest.getHeader(this.tokenHeader); if(authToken!=null) authToken =authToken.substring(7); String username = jwtTokenUtil.getUsernameFromToken(authToken); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.validateToken(authToken, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); SecurityContextHolder.getContext().setAuthentication(authentication); } } chain.doFilter(request, response); } } }

JWT工具類中,根據USER信息生成token

public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); claims.put(CLAIM_KEY_CREATED, new Date()); ...... return generateToken(claims); }

而後前端須要在每次的請求中將這個token放入請求頭中。

相關文章
相關標籤/搜索