java技术:oauth2协议

目录

一、黑马程序员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单独实现认证授权

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/13988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL的索引是什么

MySQL的索引 一、索引概述二、索引结构1.简要概述2.从二叉树说起3.再在说下B-Tree4.为什么选择BTree5.Hash又是什么6.博主被面试官经常问的题目 三、索引分类四、聚集索引&二级索引五、索引语法 一、索引概述 1.索引是帮助MySQL 高效获取数据的数据结构(有序)。在数据之外…

[STM32-HAL库]Flash库-HAL库-复杂数据读写-STM32CUBEMX开发-HAL库开发系列-主控STM32F103C6T6

目录 一、前言 二、实现步骤 1.STM32CUBEMX配置 2.导入Flash库 3.分析地址范围 4.找到可用的地址 5.写入读取普通数据 6.写入读取字符串 6.1 存储相关信息 6.2 存取多个参数 三、总结及源码 一、前言 在面对需要持久化存储的数据时&#xff0c;除了挂载TF卡&#xff0c;我们…

燃数科技前端25-40K*14薪一面超简单,下周二面啦

一面 1、自我介绍 2、低代码如何设计的 3、react路由原理 4、react生命周期 5、什么是回调地狱&#xff0c;如何解决 6、jwt和session有什么区别 7、js文件相互引用有什么问题&#xff1f;如何解决 8、一个很大的json文件&#xff0c;前端读取如何优化 面试我的不像是…

为什么说 Redis 是单线程的?——Java全栈知识(25)

为什么说 Redis 是单线程的&#xff1f; 我们常说的 Redis 是单线程的&#xff0c;但是我前面在讲持久化机制的时候又说 RDB 的持久化是通过主进程 fork 出一个子进程来实现 RDB 持久化。那么 Redis 到底是多线程还是单线程的呢&#xff1f; Redis 的网络 IO 和键值的读写是单…

数据库|基于T-SQL创建数据库

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; SQL Server用于操作数据库的编程语言为Transaction-SQL,简称T-SQL。 本节学习基于T-SQL创建数据库。以下为学习笔记。 01 打开新建查询 首先连接上数据库&#xff0c;点击【新建查询】打开新建查询窗口&#xff0c; …

C++—结构体

结构体&#xff08;struct&#xff09;&#xff0c;是一种用户自定义复合数据类型&#xff0c;可以包含不同类型的不同成员。 结构体的声明定义和使用的基本语法&#xff1a; // 声明结构体struct 结构体类型 { 成员1类型 成员1名称; ...成员N类型 成员N名称; };除声明…

【计算机视觉(2)】

基于Python的OpenCV基础入门——视频的处理 视频OpenCV视频处理操作&#xff1a;创建视频对象判断视频是否成功初始化读取视频帧获取视频特征设置视频参数声明编码器保存视频释放视频对象 视频处理基本操作的代码实现&#xff1a; 视频 视频是由一系列连续的图像帧组成的。每一…

Spring—IoC

目录 1. IoC的提出 2. Spring容器 2.1. Spring容器实现原理 2.2. Spring组件 2.2.1 XML标签方式 2.2.2. 类注解方式 2.2.3. 方法注解方式 2.3. Spring容器分类 2.3.1. BeanFactory容器 2.3.2. ApplicationContext容器 2.3.3. WebApplicationContext容器 3. Spring中…

Srping 历史

一、History of Spring and the Spring Framework Spring came into being in 2003 as a response to the complexity of the early J2EE specifications. While some consider Java EE and its modern-day successor Jakarta EE to be in competition with Spring, they are …

idea启动报错:java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory

文章目录 一、问题二、解决方法 一、问题 问题描述&#xff1a;idea整合Mybatis-plus的时候&#xff0c;启动报错&#xff1a;java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory 二、解决方法 可能原因&#xff1a;仔细检查了一下&#xff0c;发现 mybati…

《王者荣耀》4月狂揽2.34亿美元 单日流水1亿美元 全球销量第二

易采游戏网5月24日消息&#xff0c;在刚刚过去的四月&#xff0c;全球手游市场迎来了一场收益的盛宴&#xff0c;其中《王者荣耀》以其惊人的吸金能力&#xff0c;以2.34亿美元的月收入在全球手游排行榜上位列第二。4月5日&#xff0c;这款由腾讯游戏开发的多人在线战斗竞技游戏…

C++相关概念和易错语法(14)(初始化注意事项、vector、编译器向上查找规则)

1.当我们在代码中想要终止运行的话&#xff0c;我们可以采用Ctrl C或Ctrl Z&#xff0c;其中^C代表杀进程&#xff0c;^Z设置结束2.编码表&#xff1a;我们目前比较熟悉的是ASCII码编码方式&#xff0c;但是我们发现平时使用的汉字无法通过ASCII编码&#xff0c;除此之外&…

自动化测试用例结构

标准的用例结构&#xff1a; 用力标题前提条件用例步骤预期结果实际结果 测试用例对比&#xff1a;

酷开系统 | 酷开科技把握智慧先机 AI赋能家庭场景

智慧化是当今世界科技发展的前沿领域之一。现在的智慧化&#xff0c;也正在逐步成为我们日常生活的一部分。电视系统也进入了数字化时代&#xff0c;AI的应用正在不断扩展&#xff0c;其潜力似乎无穷无尽。 酷开科技深耕人工智能技术&#xff0c;在提升语音体验、强化智能家居…

第二证券:新股申购配号数什么意思?

股配号数量便是我们参与抽签的数量&#xff0c;投资者申购新股之后&#xff0c;交易所会根据持有的股票市值进行配号。 投资者的市值越大&#xff0c;申购新股的配号越多&#xff0c;其中签机会越大。主板、创业板、科创板一个申购单位是500股&#xff0c;意味着1万元的市值有…

Java 定义类型处理MySQL point类型数据

1.三个类来处理 引入maven依赖 <!-- 引入 jts 库解析 POINT --><dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version></dependency>import javax.validation.constr…

【C++入门】—— C++入门 (下)_内联函数

前言&#xff1a;在了解完前面的C基础内容后&#xff0c;马上我们就要真正不如C的学习了&#xff0c;但在之前让我们最后了解最后一点点C入门知识&#xff01;来迟的520特别篇&#xff01; 本篇主要内容&#xff1a; 内联函数 auto关键字 范围for 指针空值nullptr C入门 1. 内联…

智慧医疗时代:探索互联网医院开发的新篇章

在智慧医疗时代&#xff0c;互联网医院开发正引领着医疗服务的创新浪潮。通过将先进的技术与医疗服务相结合&#xff0c;互联网医院为患者和医生提供了全新的互动方式&#xff0c;极大地提升了医疗服务的便捷性和效率。本文将深入探讨互联网医院的开发&#xff0c;介绍其技术实…

一键部署!QQ AI 聊天机器人!支持ChatGPT、文心一言、讯飞星火、Bing、Bard、ChatGLM、POE,多账号,人设调教

随着人工智能技术的不断发展&#xff0c;智能聊天机器人已经成为我们日常生活中不可或缺的一部分。ChatGPT作为一款强大的人工智能聊天模型&#xff0c;能够为我们提供高效、便捷的聊天体验。那么&#xff0c;如何将ChatGPT接入QQ&#xff0c;实现智能聊天新体验呢&#xff1f;…

OTP8脚-全自动擦鞋机WTN6020-低成本语音方案

一&#xff0c;产品开发背景 首先&#xff0c;随着人们生活质量的提升&#xff0c;对鞋子的保养需求也日益增加。鞋子作为人们日常穿着的重要组成部分&#xff0c;其清洁度和外观状态直接影响到个人形象和舒适度。因此&#xff0c;一种能够自动清洁和擦亮鞋子的设备应运而生&am…