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放入请求头中。

相关文章
相关标签/搜索