目录
一、黑马程序员Java进阶教程快速入门Spring Security OAuth2.0认证授权详解
1、oauth服务
WebSecurityConfig
TokenConfig
AuthorizationServer
改写密码校验逻辑实现类
2、oauth2支持的四种方式:
3、oauth2授权
ResouceServerConfig
TokenConfig
4、gateway
SecurityWebFilterChain 放行 后面的授权配置会校验(授权配置也有访问控制)
TokenConfig
WebSecurityConfig
设置上下文
二、学成在线
1、GatewayAuthFilter
一、黑马程序员Java进阶教程快速入门Spring Security OAuth2.0认证授权详解
1、oauth服务
WebSecurityConfig
fuction:管理访问控制及哪些请求需要认证,以及需要哪些权限
package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// @Bean
// public UserDetailsService userDetailsService() {
// //这里配置用户信息,这里暂时使用这种方式将用户存储在内存中
// InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
// manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
// return manager;
// }@Beanpublic PasswordEncoder passwordEncoder() {
// //密码为明文方式
// return NoOpPasswordEncoder.getInstance();//spring用于加密的一个算法//授权码模式必须是加密形式return new BCryptPasswordEncoder();}@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//安全拦截机制(最重要)@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/r/r1").hasAnyAuthority("p1").antMatchers().authenticated().anyRequest().permitAll().and().formLogin();}
}
TokenConfig
jwt的相关配置就是解析生成jwt
package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;/*** @author Mr.Lan* @version 1.0* @ClassName TokenConfig$* @description TODO* @date 2024/5/21 16:59**/@Configuration
public class TokenConfig {private String SIGNING_KEY = "mq123";
// @Bean
// public TokenStore tokenStore() {
// return new InMemoryTokenStore();
// }//定义token存储方式@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}//定义jwt校验@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}}
AuthorizationServer
授权管理:主要是oauth2的配置
如:
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).authorizationCodeServices(authorizationCodeServices).tokenServices(tokenService()).allowedTokenEndpointRequestMethods(HttpMethod.POST); }
.authenticationManager(authenticationManager)在security中引入 和security联系起来(密码认证)
.authorizationCodeServices(authorizationCodeServices)支持授权码认证
.tokenServices(tokenService())令牌配置
@Override public void configure(AuthorizationServerSecurityConfigurer security) {security.tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()").allowFormAuthenticationForClients(); }
这个就是oauth2支持的接口以及允许哪些请求
生成token、校验token
@Overridepublic void configure(ClientDetailsServiceConfigurer clients)throws Exception {// // clients.withClientDetails(clientDetailsService); //后面实现clientDetailsService 注入bean后取用clients.withClientDetails(clientDetailsService);//客户端信息用内存方式 // clients.inMemory()// 使用in‐memory存储 // .withClient("c1")// client_id // .secret(new BCryptPasswordEncoder().encode("secret")) // .resourceIds("res1")//资源id // .authorizedGrantTypes("authorization_code", // "password", "client_credentials", "implicit", "refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials // .scopes("all")// 允许的授权范围与服务端匹配 // .autoApprove(false) // //加上验证回调地址 // .redirectUris("http://www.baidu.com");//注释掉内存客户端自己配置客户端}
这里的配置信息用数据库存 也可以直接配置 如果客户端一个
@Bean public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) { //采用jdbc模式 自动存放在oauth_code表中 封装类实现好的return new JdbcAuthorizationCodeServices(dataSource);
授权码用数据库存
配置完后就可以生成token以及校验token
改写密码校验逻辑实现类
package com.example.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.entity.LoginUser;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;/*** @author Mr.Lan* @version 1.0* @ClassName UserDetailsServiceImpl$* @description TODO* @date 2024/5/17 15:52**/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@AutowiredUserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {//传参是用户姓名//数据库查询用户信息以及权限信息LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>();userLambdaQueryWrapper.eq(User::getUsername,s);User user = userMapper.selectOne(userLambdaQueryWrapper);if( ObjectUtils.isEmpty(user)){throw new RuntimeException("用户不存在");}//查询权限信息ArrayList<String> permissions = new ArrayList<>(Arrays.asList("getUser", "getUser1"));LoginUser loginUser = new LoginUser(user,permissions);//返回UserDeatil对象//返回接口的实现类相当于返回了接口return loginUser;//返回后后面会校验密码}
}
package com.example.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.MapUtils;
import com.alibaba.spring.util.ObjectUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.LoginUser;
import com.example.entity.Result;
import com.example.entity.User;
import com.example.service.UserService;
import com.example.mapper.UserMapper;
import com.example.utils.RedisTemplateUtils;
import io.jsonwebtoken.Claims;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapProperties;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;import static com.example.utils.JwtUtils.generateJwt;/**
* @author Admin
* @description 针对表【user】的数据库操作Service实现
* @createDate 2024-05-16 21:03:01
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@AutowiredAuthenticationManager authenticationManager;@AutowiredUserMapper userMapper;@AutowiredRedisTemplateUtils redisTemplateUtils;//authenticationManager在login的方法(这里是实现类)调用,就继续传递@Overridepublic Result login(User user) {//当参数是接口时可以传接口的实现类 创建实现类封装传递 Authentication//new UsernamePasswordAuthenticationToken()的两个参数 Object 后面要用UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());//这里将返回的时认证后的结果Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);if(Objects.isNull(authenticate)){throw new RuntimeException("认证失败");}BeanUtils.copyProperties(authenticate.getPrincipal(),user);//获取返回中的信息 加密返回tokenHashMap<String, Object> claims = new HashMap<>();LoginUser principal = (LoginUser)authenticate.getPrincipal();claims.put("userId",principal.getUser().getId());String token = generateJwt(claims);//将token存入redis 并以userId为keyredisTemplateUtils.set("login:"+principal.getUser().getId(),principal,432000L);HashMap<String, String> map = new HashMap<>();map.put("token",token);
// String jsonString = JSON.toJSONString(map);return Result.success(400,"登陆成功",map);}@Overridepublic Result loginOut() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();LoginUser principal = (LoginUser)authentication.getPrincipal();String userId = principal.getUser().getId();//删除redis中的tokentry {redisTemplateUtils.del("login:"+userId);} catch (Exception e) {e.printStackTrace();return Result.error("退出登录失败");}return Result.success("成功退出登录");}
}
2、oauth2支持的四种方式:
###授权码模式
###申请授权码
GET {{auth1}}/auth/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com###申请令牌
POST {{auth1}}/auth/oauth/token?client_id=c1&client_secret=secret&grant_type=authorization_code&code=yHKHC1&redirect_uri=http://www.baidu.com
Content-Type: application/json{}###简化模式
GET http://localhost:8041/auth/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com
Accept: application/json###密码模式
POST {{auth1}}/auth1/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=lanjie&password=lanjie
Accept: application/json###客户端模式
POST {{auth1}}/auth/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials
Accept: application/json
授权码、密码、简化、客户端
3、oauth2授权
ResouceServerConfig
资源服务授权(先校验token后授权) 主要是授权
package cn.itcast.order.config;import cn.itcast.order.filter.TokenAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** @author Mr.Lan* @version 1.0* @ClassName ResouceServerConfig$* @description TODO* @date 2024/5/22 13:28**/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class ResouceServerConfigJwt extends ResourceServerConfigurerAdapter {//资源服务标识public static final String RESOURCE_ID = "res1";@AutowiredTokenStore tokenStore;@AutowiredTokenAuthenticationFilter tokenAuthenticationFilter;//服务资源配置@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(RESOURCE_ID)//资源 id
// .tokenServices(tokenService()).tokenStore(tokenStore).stateless(true);}
//服务端访问控制@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/*").access("#oauth2.hasAnyScope('all')").antMatchers("/**").authenticated()//所有/r/**的请求必须认证通过.anyRequest().permitAll();
// http.addFilterBefore(tokenAuthenticationFilter, OAuth2AuthenticationProcessingFilter.class);}//服务端解析令牌通过远程调用
// @Bean
// public ResourceServerTokenServices tokenService() {
使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id,client_secret
// RemoteTokenServices service=new RemoteTokenServices();
// service.setCheckTokenEndpointUrl("http://localhost:8041/auth/oauth/check_token");
// service.setClientId("c1");
// service.setClientSecret("secret");
// return service;
// }}
TokenConfig
package cn.itcast.order.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;/*** @author Administrator* @version 1.0**/
@Configuration
public class TokenConfigJwt {String SIGNING_KEY = "mq123";// @Bean
// public TokenStore tokenStore() {
// //使用内存存储令牌(普通令牌)
// return new InMemoryTokenStore();
// }@Autowiredprivate JwtAccessTokenConverter accessTokenConverter;@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}}
4、gateway
SecurityWebFilterChain 放行 后面的授权配置会校验(授权配置也有访问控制)
package com.example.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;/*** @author Mr.Lan* @version 1.0* @ClassName ResouceServerConfig$* @description TODO* @date 2024/5/22 16:32**/
@Configuration
public class ResouceServerConfig {public static final String RESOURCE_ID = "res1";/*** 统一认证服务(UAA) 资源拦截*/@Configuration@EnableResourceServerpublic class UAAServerConfig extendsResourceServerConfigurerAdapter {@Autowiredprivate TokenStore tokenStore;@Overridepublic void configure(ResourceServerSecurityConfigurer resources){resources.tokenStore(tokenStore).resourceId(RESOURCE_ID).stateless(true);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/uaa/**").permitAll();}}/*** 订单服务*/@Configuration@EnableResourceServerpublic class OrderServerConfig extendsResourceServerConfigurerAdapter {@Autowiredprivate TokenStore tokenStore;@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.tokenStore(tokenStore).resourceId(RESOURCE_ID).stateless(true);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/order/**").access("#oauth2.hasScope('ROLE_API')");}}}
TokenConfig
package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;/*** @author Mr.Lan* @version 1.0* @ClassName TokenConfig$* @description TODO* @date 2024/5/21 16:59**/@Configuration
public class TokenConfig {private String SIGNING_KEY = "mq123";
// @Bean
// public TokenStore tokenStore() {
// return new InMemoryTokenStore();
// }//定义token存储方式@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}//定义jwt校验@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}}
WebSecurityConfig
package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;@EnableWebFluxSecurity
@Configuration
public class WebSecurityConfig {//安全拦截配置@Beanpublic SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) {return http.authorizeExchange().pathMatchers("/**").permitAll().anyExchange().authenticated().and().csrf().disable().build();}
}
ps:改视频使用的是网关与服务之间进行明文token(记得设置资源的访问控制为都放行,网关以及认证授权了)
设置上下文
SecurityContextHolder.getContext()
package cn.itcast.order.filter;import cn.itcast.order.pojo.UserDTO;
import cn.itcast.order.utils.EncryptUtil;
import cn.itcast.order.utils.HeaderMapRequestWrapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;/*** @author Mr.Lan* @version 1.0* @ClassName TokenAuthenticationFilter$* @description TODO* @date 2024/5/23 11:47**/
@Component
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TokenAuthenticationFilter extends OncePerRequestFilter{@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponsehttpServletResponse, FilterChain filterChain) throws ServletException, IOException {Enumeration<String> headerNames = httpServletRequest.getHeaderNames();String token=null;while (headerNames.hasMoreElements()) {String headerName = headerNames.nextElement();String headerValue = httpServletRequest.getHeader(headerName);if(headerName.equals("json-token")){token=headerValue;}// 处理请求头信息log.info("{}:{}",headerName,headerValue);}String jwt=httpServletRequest.getHeader("jwt");
//原有的请求头依然存在HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(httpServletRequest);requestWrapper.addHeader("Authorization",jwt);
// String token = httpServletRequest.getHeader("json‐token");if (token != null){//1.解析tokenString json = EncryptUtil.decodeUTF8StringBase64(token);JSONObject userJson = JSON.parseObject(json);UserDTO user = new UserDTO();user.setUsername(userJson.getString("principal"));JSONArray authoritiesArray = userJson.getJSONArray("authorities");String [] authorities = authoritiesArray.toArray( newString[authoritiesArray.size()]);
// 2.新建并填充authenticationUsernamePasswordAuthenticationToken authentication = newUsernamePasswordAuthenticationToken(user, null, AuthorityUtils.createAuthorityList(authorities));authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));//3.将authentication保存进安全上下文SecurityContextHolder.getContext().setAuthentication(authentication);}filterChain.doFilter(requestWrapper, httpServletResponse);}
}
上下文如果授权配置ResouceServerConfig生效 会自动生成上下文
而资源服务已经关闭了授权配置 因此上下文需要明文token传递 然后解析
目的是 资源服务可以借此获取用户信息
完结!!!!
网关的token是否会转发
二、学成在线
区别: 在网关设置了全局过滤器实现白名单以及校验 没有使用资源配置校验
1、GatewayAuthFilter
package com.xuecheng.gateway.config;import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;/*** @author Mr.M* @version 1.0* @description 网关认证过虑器* @date 2022/9/27 12:10*/
@Component
@Slf4j
public class GatewayAuthFilter implements GlobalFilter, Ordered {//白名单private static List<String> whitelist = null;static {//加载白名单try (InputStream resourceAsStream = GatewayAuthFilter.class.getResourceAsStream("/security-whitelist.properties");) {Properties properties = new Properties();properties.load(resourceAsStream);Set<String> strings = properties.stringPropertyNames();whitelist= new ArrayList<>(strings);} catch (Exception e) {log.error("加载/security-whitelist.properties出错:{}",e.getMessage());e.printStackTrace();}}@Autowiredprivate TokenStore tokenStore;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String requestUrl = exchange.getRequest().getPath().value();AntPathMatcher pathMatcher = new AntPathMatcher();//白名单放行for (String url : whitelist) {if (pathMatcher.match(url, requestUrl)) {return chain.filter(exchange);}}//检查token是否存在String token = getToken(exchange);if (StringUtils.isBlank(token)) {return buildReturnMono("没有认证",exchange);}//判断是否是有效的tokenOAuth2AccessToken oAuth2AccessToken;try {oAuth2AccessToken = tokenStore.readAccessToken(token);boolean expired = oAuth2AccessToken.isExpired();if (expired) {return buildReturnMono("认证令牌已过期",exchange);}return chain.filter(exchange);} catch (InvalidTokenException e) {log.info("认证令牌无效: {}", token);return buildReturnMono("认证令牌无效",exchange);}}/*** 获取token*/private String getToken(ServerWebExchange exchange) {String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization");if (StringUtils.isBlank(tokenStr)) {return null;}String token = tokenStr.split(" ")[1];if (StringUtils.isBlank(token)) {return null;}return token;}private Mono<Void> buildReturnMono(String error, ServerWebExchange exchange) {ServerHttpResponse response = exchange.getResponse();String jsonString = JSON.toJSONString(new RestErrorResponse(error));byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8);DataBuffer buffer = response.bufferFactory().wrap(bits);response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));}@Overridepublic int getOrder() {return 0;}
}
未完!
有关springsecurity单独实现认证授权