文章目录微服务用户鉴权拦截继承测试本章代码已分享至Gitee: https://gitee.com/lengcz/distributed-security01.git微服务用户鉴权拦截当微服务收到明文token时应该怎么鉴权拦截呢自己实现了一个filter自己解析明文token自己定义一套资源访问策略能不能适配 Spring Security呢是不是突然想起了嵌满我们实现的Spring Security基于token认证例子。这里拿统一用户服务作为网关下游微服务对它进行改造增加微服务用户鉴权拦截功能。1 增加测试资源OrderController增加一下endpointRestControllerpublicclassOrderController{GetMapping(value/r1)PreAuthorize(hasAuthority(p1))//拥有p1权限方可访问此urlpublicStringr1(){//获取用户身份信息UserDTOuserDTO(UserDTO)SecurityContextHolder.getContext().getAuthentication().getPrincipal();returnuserDTO.getUsername()访问资源1;}GetMapping(value/r2)PreAuthorize(hasAnyAuthority(p2))// 拥有p2权限方可发个文publicStringr2(){return访问资源2;}GetMapping(value/r3)publicStringr3(){return访问资源3;}}增加UserDTOimportlombok.Data;/** * 用户信息 */DatapublicclassUserDTO{/** * 用户id */privateStringid;/** * 用户名 */privateStringusername;/** * 手机号 */privateStringmobile;/** * 姓名 */privateStringfullname;}2spring security配置开启方法保护并增加Spring配置策略除了/login方法不受保护统一认证要调用)其他资源全部需要认证才能访问。Overridepublicvoidconfigure(HttpSecurityhttp)throwsException{http.authorizeRequests().antMatchers(/**).access(#oauth2.hasScope(ROLE_ADMIN)).and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}综合上面的配置共定义了三个资源了拥有p1权限可以访问资源r1拥有p2权限可以访问资源r2只要认证通过就能访问资源r3 。3定义filter拦截token并形成Spring Security的Authenication对象importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONArray;importcom.alibaba.fastjson.JSONObject;importcom.it2.security.distributed.order.model.UserDTO;importcom.it2.security.distributed.order.util.EncryptUtil;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.authority.AuthorityUtils;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.security.web.authentication.WebAuthenticationDetailsSource;importorg.springframework.stereotype.Component;importorg.springframework.web.filter.OncePerRequestFilter;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;ComponentpublicclassTokenAuthenticationFilterextendsOncePerRequestFilter{OverrideprotectedvoiddoFilterInternal(HttpServletRequesthttpServletRequest,HttpServletResponsehttpServletResponse,FilterChainfilterChain)throwsServletException,IOException{//解析出header里的tokenStringtokenhttpServletRequest.getHeader(json-token);if(token!null){StringjsonEncryptUtil.decodeUTF8StringBase64(token);JSONObjectjsonObjectJSON.parseObject(json);UserDTOuserJsonnewUserDTO();//用户身份信息StringprincipaljsonObject.getString(principal);userJson.setUsername(principal);//用户权限信息JSONArrayauthoritiesjsonObject.getJSONArray(authorities);String[]arrauthorities.toArray(newString[authorities.size()]);// 2 新建并填充authentication,将用户信息和权限填充到token对象中UsernamePasswordAuthenticationTokenauthenticationnewUsernamePasswordAuthenticationToken(userJson,null,AuthorityUtils.createAuthorityList(arr));authentication.setDetails(newWebAuthenticationDetailsSource().buildDetails(httpServletRequest));// 将authentication 填充到安全上下文SecurityContextHolder.getContext().setAuthentication(authentication);}filterChain.doFilter(httpServletRequest,httpServletResponse);}}经过上面的拦截器资源服务中就可以方便的获取用户的身份信息//获取用户身份信息UserDTOuserDTO(UserDTO)SecurityContextHolder.getContext().getAuthentication().getPrincipal();继承测试本案例测试过程描述1 采用OAuth2.0的密码模式从UAA获取token2 使用该token通过网关访问订单服务的测试资源1过网关访问UAA 的授权及获取令牌获取token。http://localhost:53010/uaa/oauth/authorize?response_typecodeclient_idc1令牌endpointhttp://localhost:53010/uaa/oauth/token密码模式获取令牌使用令牌访问r1资源(注意经过网关服务)可以看到在应用服务用能访问到用户的信息。