Zuul + Oauth 2 实现鉴权功能 
技术简介 
oauth2 
OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. This specification and its extensions are being developed within the IETF OAuth Working Group.
 
OAuth 2.1 is an in-progress effort to consolidate OAuth 2.0 and many common extensions under a new name.
 
zuul 
Zuul is the front door for all requests from devices and web sites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security. It also has the ability to route requests to multiple Amazon Auto Scaling Groups as appropriate.
 
技术版本选择 
1 2 3 4 5 6 7 8 9 10 <dependency >        <groupId > org.springframework.cloud</groupId >         <artifactId > spring-cloud-starter-netflix-zuul</artifactId >         <version > 2.0.1.RELEASE</version >     </dependency >     <dependency >         <groupId > org.springframework.cloud</groupId >         <artifactId > spring-cloud-starter-netflix-eureka-client</artifactId >         <version > 2.0.1.RELEASE</version >     </dependency >  
 
1 2 3 4 5 6 7 8 9 10 <dependency >         <groupId > org.springframework.cloud</groupId >          <artifactId > spring-cloud-starter-security</artifactId >          <version > 2.0.0.RELEASE</version >      </dependency >      <dependency >          <groupId > org.springframework.cloud</groupId >          <artifactId > spring-cloud-starter-oauth2</artifactId >          <version > 2.0.0.RELEASE</version >      </dependency >  
 
实现 
1.网关搭建
见:<<Swagger + Zuul 整合微服务接口文档>> 一文
 
 
2.oauth 配置
在 application.yml 文件中配置 auth 服务 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 auth:   tokenValiditySeconds:  1200     clientId:  domain    clientSecret:  domain    cookieDomain:  domain.com    cookieMaxAge:  -1  encrypt:   key-store:      location:  classpath:rs.keystore      secret:  domainkeystore      alias:  domainkey      password:  domain  
 
security 配置,放行登陆、获取验证码等接口 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package  com.czq.auth.config;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.core.annotation.Order;import  org.springframework.security.authentication.AuthenticationManager;import  org.springframework.security.config.annotation.web.builders.HttpSecurity;import  org.springframework.security.config.annotation.web.builders.WebSecurity;import  org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import  org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import  org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import  org.springframework.security.crypto.password.PasswordEncoder;@Configuration @EnableWebSecurity @Order(-1) class  WebSecurityConfig  extends  WebSecurityConfigurerAdapter  {    @Override      public  void  configure (WebSecurity web)  throws  Exception {         web.ignoring().antMatchers("/userlogin" ,"/userlogout" ,"/userjwt" );     }     @Bean      @Override      public  AuthenticationManager authenticationManagerBean ()  throws  Exception {         AuthenticationManager  manager  =  super .authenticationManagerBean();         return  manager;     }          @Bean      public  PasswordEncoder passwordEncoder ()  {         return  new  BCryptPasswordEncoder ();     }     @Override      public  void  configure (HttpSecurity http)  throws  Exception {         http.csrf().disable()                 .httpBasic().and()                 .formLogin()                 .and()                 .authorizeRequests().anyRequest().permitAll();     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package  com.czq.auth.config;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.cloud.bootstrap.encrypt.KeyProperties;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;import  org.springframework.security.authentication.AuthenticationManager;import  org.springframework.security.core.userdetails.UserDetailsService;import  org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import  org.springframework.security.crypto.password.PasswordEncoder;import  org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;import  org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;import  org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;import  org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;import  org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;import  org.springframework.security.oauth2.provider.ClientDetailsService;import  org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;import  org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;import  org.springframework.security.oauth2.provider.token.TokenStore;import  org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;import  org.springframework.security.oauth2.provider.token.store.JwtTokenStore;import  org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;import  javax.annotation.Resource;import  javax.sql.DataSource;import  java.security.KeyPair;@Configuration @EnableAuthorizationServer class  AuthorizationServerConfig  extends  AuthorizationServerConfigurerAdapter  {    @Autowired      private  DataSource dataSource;          @Autowired      private  JwtAccessTokenConverter jwtAccessTokenConverter;     @Autowired      UserDetailsService userDetailsService;     @Autowired      AuthenticationManager authenticationManager;     @Autowired      TokenStore tokenStore;     @Autowired      private  CustomUserAuthenticationConverter customUserAuthenticationConverter;          @Bean("keyProp")      public  KeyProperties keyProperties () {         return  new  KeyProperties ();     }     @Resource(name = "keyProp")      private  KeyProperties keyProperties;          @Bean      public  ClientDetailsService clientDetails ()  {         return  new  JdbcClientDetailsService (dataSource);     }     @Override      public  void  configure (ClientDetailsServiceConfigurer clients)  throws  Exception {         clients.jdbc(this .dataSource).clients(this .clientDetails());     }     @Bean      @Autowired      public  TokenStore tokenStore (JwtAccessTokenConverter jwtAccessTokenConverter)  {         return  new  JwtTokenStore (jwtAccessTokenConverter);     }     @Bean      public  JwtAccessTokenConverter jwtAccessTokenConverter (CustomUserAuthenticationConverter customUserAuthenticationConverter)  {         JwtAccessTokenConverter  converter  =  new  JwtAccessTokenConverter ();         KeyPair  keyPair  =  new  KeyStoreKeyFactory                  (keyProperties.getKeyStore().getLocation(), keyProperties.getKeyStore().getSecret().toCharArray())                 .getKeyPair(keyProperties.getKeyStore().getAlias(),keyProperties.getKeyStore().getPassword().toCharArray());         converter.setKeyPair(keyPair);                  DefaultAccessTokenConverter  accessTokenConverter  =  (DefaultAccessTokenConverter) converter.getAccessTokenConverter();         accessTokenConverter.setUserTokenConverter(customUserAuthenticationConverter);         return  converter;     }          @Override      public  void  configure (AuthorizationServerEndpointsConfigurer endpoints)  throws  Exception {         endpoints.accessTokenConverter(jwtAccessTokenConverter)                 .authenticationManager(authenticationManager)                 .tokenStore(tokenStore)                 .userDetailsService(userDetailsService);     }          @Override      public  void  configure (AuthorizationServerSecurityConfigurer oauthServer)  throws  Exception {         oauthServer.allowFormAuthenticationForClients()                 .passwordEncoder(new  BCryptPasswordEncoder ())                 .tokenKeyAccess("permitAll()" )                 .checkTokenAccess("permitAll()" );     }     @Bean      public  PasswordEncoder passwordEncoder () {         return   new  BCryptPasswordEncoder ();     } } 
 
配置自定义的 CustomUserAuthenticationConverter 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package  com.czq.auth.config;import  com.czq.auth.service.UserJwt;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.security.core.Authentication;import  org.springframework.security.core.authority.AuthorityUtils;import  org.springframework.security.core.userdetails.UserDetails;import  org.springframework.security.core.userdetails.UserDetailsService;import  org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;import  org.springframework.stereotype.Component;import  java.util.LinkedHashMap;import  java.util.Map;@Component public  class  CustomUserAuthenticationConverter  extends  DefaultUserAuthenticationConverter  {    @Autowired      UserDetailsService userDetailsService;     @Override      public  Map<String, ?> convertUserAuthentication(Authentication authentication) {         LinkedHashMap  response  =  new  LinkedHashMap ();         String  name  =  authentication.getName();         response.put("username" , name);         Object  principal  =  authentication.getPrincipal();         UserJwt  userJwt  =  null ;         if (principal instanceof   UserJwt){             userJwt = (UserJwt) principal;         }else {                          UserDetails  userDetails  =  userDetailsService.loadUserByUsername(name);             userJwt = (UserJwt) userDetails;         }         if  (authentication.getAuthorities() != null  && !authentication.getAuthorities().isEmpty()) {             response.put("authorities" , AuthorityUtils.authorityListToSet(authentication.getAuthorities()));         }         return  response;     } } 
 
3.Oauth 令牌生成
在用户登录时申请 token
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78     private  AuthToken applyToken (String username, String password, String clientId, String clientSecret)  throws  UnsupportedEncodingException {         ServiceInstance  serviceInstance  =  loadBalancerClient.choose(ServiceList.AUTH_SERVICE);         if  (serviceInstance == null ){             LOGGER.error("choose an auth instance null" );             ExceptionCast.cast(AuthCode.AUTH_LOGIN_AUTHSERVER_NOTFOUND);         }         URI  uri  =  serviceInstance.getUri();         String  authUrl  =  uri+ "/auth/oauth/token" ;         MultiValueMap<String,String> formData = new  LinkedMultiValueMap <>();         formData.add("grant_type" ,"password" );         formData.add("username" ,username);         formData.add("password" ,password);         MultiValueMap<String,String> header = new  LinkedMultiValueMap <>();         header.add("Authorization" ,httpbasic(clientId,clientSecret));                  restTemplate.setErrorHandler(new  DefaultResponseErrorHandler (){             @Override              public  void  handleError (URI url, HttpMethod method, ClientHttpResponse response)  throws  IOException {                                  if (response.getRawStatusCode()!=400  && response.getRawStatusCode()!=401 ){                     super .handleError(response);                 }             }         });         Map  map  =  null ;         try  {             HttpEntity<MultiValueMap<String, String>> httpEntity = new  HttpEntity <>(formData, header);             ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(authUrl, HttpMethod.POST,                     httpEntity, Map.class);             map = mapResponseEntity.getBody();         } catch  (RestClientException e) {             e.printStackTrace();             LOGGER.error("request oauth_token_password error: {}" ,e.getMessage());             e.printStackTrace();             ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);         }         if  (map == null  ||                 map.get("access_token" ) == null  ||                 map.get("refresh_token" ) == null  ||                 map.get("jti" ) == null ){             String  error_description  =  (String) map.get("error_description" );             if  (StringUtils.isNotEmpty(error_description)) {                 if (error_description.equals("坏的凭证" )){                     ExceptionCast.cast(AuthCode.AUTH_CREDENTIAL_ERROR);                 }   else  if  (error_description.indexOf("UserDetailsService returned null" ) > 0 ){                     ExceptionCast.cast(AuthCode.AUTH_ACCOUNT_NOTEXISTS);                 }             }             ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);         }         AuthToken  authToken  =  new  AuthToken ();         String  jwt_token  =  (String) map.get("access_token" );         String  refresh_token  =  (String) map.get("refresh_token" );                  String  access_token  =  (String) map.get("jti" );         authToken.setJwt_token(jwt_token);         authToken.setAccess_token(access_token);         authToken.setRefresh_token(refresh_token);         return  authToken; 
 
在获取到令牌后,存储至 redis 中。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44     public  AuthToken login (String username, String password, String clientId, String clientSecret)  throws  UnsupportedEncodingException {   AuthToken  authToken  =  applyToken(username,password,clientId,clientSecret);         if  (authToken == null  ){             ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);         }   String  access_token  =  authToken.getAccess_token();         String  content  =  (String) JSON.toJSONString(authToken);         boolean  saveTokenResult  =  saveToken(access_token,content,tokenValiditySeconds);         if  (!saveTokenResult){             ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);         }         return  authToken;     }        private  boolean  saveToken (String access_token, String content, long  ttl)  {         String  key  =  "user_token:"  + access_token;         stringRedisTemplate.boundValueOps(key).set(content,ttl, TimeUnit.SECONDS);         Long  expire  =  stringRedisTemplate.getExpire(key,TimeUnit.SECONDS);         return  expire > 0 ;     } 
 
保存到 redis 后,通过 cookie 返回至前端
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17     private  void  saveCookie (String access_token)  {         HttpServletResponse  response  =  ((ServletRequestAttributes)                 RequestContextHolder.getRequestAttributes()).getResponse();         assert  response != null ;         CookieUtil.addCookie(response,cookieDomain,"/" ,                 "uid" ,access_token,cookieMaxAge,false );     } 
 
最终返回 token 至前端,前端通过携带 cookie 获取 jwt 令牌
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23    public  AuthToken getUserToken (String access_token)  {        String  userToken  =  "user_token:"  + access_token;        String  userTokenString  =   stringRedisTemplate.opsForValue().get(userToken);        if  (userToken != null ){            AuthToken  authToken  =  null ;            try  {                authToken = JSON.parseObject(userTokenString,AuthToken.class);            }catch  (Exception e){                LOGGER.error("getUserToken from redis and execute JSON.parseObject error {}" ,e.getMessage());                e.printStackTrace();            }            return  authToken;        }        return  null ;    } 
 
4.网关配置过滤规则,放行登录等接口
在过滤规则中,对不符合要求接口予以拦截并返回 403。
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 package  com.czq.gateway.filter;import  com.alibaba.fastjson.JSON;import  com.czq.common.model.response.CommonCode;import  com.czq.common.model.response.ResponseResult;import  com.czq.model.auth.ext.*;import  com.netflix.zuul.ZuulFilter;import  com.netflix.zuul.context.RequestContext;import  com.netflix.zuul.exception.ZuulException;import  lombok.extern.slf4j.Slf4j;import  org.apache.commons.lang3.StringUtils;import  org.slf4j.Logger;import  org.slf4j.LoggerFactory;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.boot.web.client.RestTemplateBuilder;import  org.springframework.http.*;import  org.springframework.stereotype.Component;import  org.springframework.util.AntPathMatcher;import  org.springframework.util.LinkedMultiValueMap;import  org.springframework.util.MultiValueMap;import  org.springframework.util.PathMatcher;import  org.springframework.web.client.RestTemplate;import  javax.servlet.http.HttpServletRequest;import  javax.servlet.http.HttpServletResponse;import  java.util.ArrayList;import  java.util.List;import  java.util.Optional;@Slf4j @Component public  class  LoginFilter  extends  ZuulFilter  {    List<String> paths = new  ArrayList <>();     private  static  final  Logger  LOG  =  LoggerFactory.getLogger(LoginFilter.class);     public  LoginFilter ()  {         super ();         paths.add("/**/auth/oauth/check_token" );         paths.add("/**/auth/oauth/token" );         paths.add("/**/auth/userlogin" );         paths.add("/**/auth/userjwt" );         paths.add("/**/manage/captcha" );         paths.add("/**/manage/verification" );         paths.add("/ui/**" );         paths.add("/**/swagger**/**" );         paths.add("/**/v2/api-docs" );         paths.add("/**/*.css" );         paths.add("/**/*.jpg" );         paths.add("/**/*.png" );         paths.add("/**/*.gif" );         paths.add("/**/*.js" );         paths.add("/**/*.svg" );     }               @Override      public  String filterType ()  {         return  "pre" ;     }     @Override      public  int  filterOrder ()  {         return  1 ;     }     @Override      public  boolean  shouldFilter ()  {         RequestContext  requestContext  =  RequestContext.getCurrentContext();         HttpServletRequest  request  =  requestContext.getRequest();         String  uri  =  request.getRequestURI();         PathMatcher  matcher  =  new  AntPathMatcher ();         Optional<String> optional = paths.stream().filter(t -> matcher.match(t, uri)).findFirst();         return  !optional.isPresent();     }     @Override      public  Object run ()  throws  ZuulException {         RequestContext  requestContext  =  RequestContext.getCurrentContext();         HttpServletResponse  httpServletResponse  =  requestContext.getResponse();         HttpServletRequest  httpServletRequest  =  requestContext.getRequest();         String  authorization  =  httpServletRequest.getHeader("Authorization" );         if  (StringUtils.isEmpty(authorization)) {             requestContext.setSendZuulResponse(false );             requestContext.setResponseStatusCode(200 );             ResponseResult  unauthenticated  =  new  ResponseResult (CommonCode.UNAUTHENTICATED);             String  jsonString  =  JSON.toJSONString(unauthenticated);             requestContext.setResponseBody(jsonString);             requestContext.getResponse().setContentType("application/json;charset=UTF‐8" );             return  null ;         }         if  (!StringUtils.startsWithIgnoreCase(authorization, "bearer " )) {             log.error("http request header authorization is error" );             return  null ;         }         try  {             TokenInfo  tokenInfo  =  getTokenInfo(authorization);             httpServletRequest.setAttribute("token" , tokenInfo);         } catch  (Exception e) {             log.error("token check error !" , e);         }         return  null ;     } } 
 
对携带令牌的请求通过请求鉴权服务验证 token 合法后放行至下一过滤规则,反之返回 token 检查失败。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18   private  TokenInfo getTokenInfo (String authorization)  {         String  url  =  "http://localhost:50201/api/v1.0.1/auth-service/auth/oauth/check_token" ;         String  token  =  StringUtils.substringAfter(authorization, "Bearer " );         HttpHeaders  headers  =  new  HttpHeaders ();         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);                  headers.add(HttpHeaders.AUTHORIZATION, "Bearer "  + token);                  headers.add(HttpHeaders.CONTENT_TYPE,"application/json" );         RestTemplateBuilder  builder  =  new  RestTemplateBuilder ();         RestTemplate  restTemplate  =  builder.basicAuthorization("RsWebApp" , "RsWebApp" ).build();         MultiValueMap<String, String> params = new  LinkedMultiValueMap <>();         params.add("token" , token);         HttpEntity<MultiValueMap<String, String>> httpEntity = new  HttpEntity <>(params, headers);         ResponseEntity<TokenInfo> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, TokenInfo.class);         return  exchange.getBody();     } 
 
5.网关鉴权过滤规则
拦截请求,校验 token 是否过期;对符合要求的请求在 header 中添加 jti (java web token identity)并予以放行
 
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 package  com.czq.gateway.filter;import  com.czq.model.auth.ext.TokenInfo;import  com.netflix.zuul.ZuulFilter;import  com.netflix.zuul.context.RequestContext;import  com.netflix.zuul.exception.ZuulException;import  lombok.extern.slf4j.Slf4j;import  org.apache.commons.lang.StringUtils;import  org.slf4j.Logger;import  org.slf4j.LoggerFactory;import  org.springframework.stereotype.Component;import  org.springframework.util.AntPathMatcher;import  org.springframework.util.PathMatcher;import  javax.servlet.http.HttpServletRequest;import  java.util.ArrayList;import  java.util.List;import  java.util.Optional;@Slf4j @Component public  class  AuthorizationFilter  extends  ZuulFilter  {    List<String> paths = new  ArrayList <>();     private  static  final  Logger  LOG  =  LoggerFactory.getLogger(LoginFilter.class);     public  AuthorizationFilter ()  {         super ();         paths.add("/**/auth/oauth/check_token" );         paths.add("/**/auth/oauth/token" );         paths.add("/**/auth/userlogin" );         paths.add("/**/auth/userjwt" );         paths.add("/**/manage/captcha" );         paths.add("/**/manage/verification" );         paths.add("/ui/**" );         paths.add("/**/swagger**/**" );         paths.add("/**/v2/api-docs" );         paths.add("/**/*.css" );         paths.add("/**/*.jpg" );         paths.add("/**/*.png" );         paths.add("/**/*.gif" );         paths.add("/**/*.js" );         paths.add("/**/*.svg" );     }     @Override      public  boolean  shouldFilter ()  {         RequestContext  requestContext  =  RequestContext.getCurrentContext();         HttpServletRequest  request  =  requestContext.getRequest();         String  uri  =  request.getRequestURI();         PathMatcher  matcher  =  new  AntPathMatcher ();         Optional<String> optional = paths.stream().filter(t -> matcher.match(t, uri)).findFirst();         return  !optional.isPresent();     }     @Override      public  Object run ()  throws  ZuulException {         log.info("authorization start" );         RequestContext  requestContext  =  RequestContext.getCurrentContext();         HttpServletRequest  request  =  requestContext.getRequest();         if  (isNeedAuth(request)) {                          TokenInfo  tokenInfo  =  (TokenInfo) request.getAttribute("token" );                          if  (tokenInfo != null  && tokenInfo.isActive()) {                 if  (!hasPermission(tokenInfo, request)) {                     log.info("audit log update fail 403" );                     handleError(403 , requestContext);                 }                 requestContext.addZuulRequestHeader("token" , tokenInfo.getJti());             } else  {                 if  (!StringUtils.startsWith(request.getRequestURI(), "/token" )) {                     log.info("audit log update fail 401" );                     handleError(401 , requestContext);                 }             }         }         return  null ;     }     private  void  handleError (int  status, RequestContext requestContext)  {         requestContext.getResponse().setContentType("application/json" );         requestContext.setResponseStatusCode(status);         requestContext.setResponseBody("{\"message\":\"auth fail\"}" );         requestContext.setSendZuulResponse(false );     }     private  boolean  hasPermission (TokenInfo tokenInfo, HttpServletRequest request)  {         return  true ;      }     private  boolean  isNeedAuth (HttpServletRequest request)  {         return  true ;     }     @Override      public  String filterType ()  {         return  "pre" ;     }     @Override      public  int  filterOrder ()  {         return  3 ;     } } 
 
TokenInfo.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  com.czq.model.auth.ext;import  lombok.Data;import  lombok.NoArgsConstructor;import  lombok.ToString;import  java.util.List;@Data @ToString @NoArgsConstructor public  class  TokenInfo  {    String userpic;     String user_name;     List<String> scope;     String name;     String utype;     boolean  active;     String id;     long  exp;     String jti;     String client_id; } 
 
AuthToken.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  com.czq.model.auth.ext;import  lombok.Data;import  lombok.NoArgsConstructor;import  lombok.ToString;@Data @ToString @NoArgsConstructor public  class  AuthToken  {    String access_token;     String refresh_token;     String jwt_token; } 
 
about me 个人微信 
wechat offical 微信公众号