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.pswp.cn/web/13988.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/13988.shtml
英文地址,請注明出處:http://en.pswp.cn/web/13988.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端面試題日常練-day19 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末。 1. AJAX是什么的縮寫&#xff1f; A. Asynchronous JavaScript and XMLB. Asynchronous JavaScript and XHTMLC. Asynchronous Java and XMLD. Asynchronous Java and XHTML2. 下列哪個方法用于創建…

SpringCloudAlibaba 動態讀取配置文件的信息

傳統讀取方式&#xff1a; 在application.properties中寫入要讀取的內容&#xff0c;如下&#xff1a; coupon.user.nameTom coupon.user.age27 接口引入處&#xff1a; Value("${coupon.user.name}")private String name;Value("${coupon.user.age}")p…

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 和鍵值的讀寫是單…

力扣:1306. 跳躍游戲 III

1306. 跳躍游戲 III 這里有一個非負整數數組 arr&#xff0c;你最開始位于該數組的起始下標 start 處。當你位于下標 i 處時&#xff0c;你可以跳到 i arr[i] 或者 i - arr[i]。 請你判斷自己是否能夠跳到對應元素值為 0 的 任一 下標處。 注意&#xff0c;不管是什么情況下…

數據庫|基于T-SQL創建數據庫

哈嘍&#xff0c;你好啊&#xff0c;我是雷工&#xff01; SQL Server用于操作數據庫的編程語言為Transaction-SQL,簡稱T-SQL。 本節學習基于T-SQL創建數據庫。以下為學習筆記。 01 打開新建查詢 首先連接上數據庫&#xff0c;點擊【新建查詢】打開新建查詢窗口&#xff0c; …

appium-driver方法待整理。。

app C:\Users\v-hongweishi\AppData\Local\Programs\Xmind\Xmind.exe deviceName DESKTOP-7NJ1ENB platformName Windows 應用程序ID&#xff08;AppId&#xff09;是應用程序用戶模型 ID (AppUserModelID)&#xff0c;簡稱 AUMID Outlook …

Leetcode 113:路徑總和II

給你二叉樹的根節點 root 和一個整數目標和 targetSum &#xff0c;找出所有 從根節點到葉子節點 路徑總和等于給定目標和的路徑。 葉子節點 是指沒有子節點的節點。 public static List<List<Integer>> pathSum(TreeNode root, int targetSum) {List<List&l…

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 …

nginx 配置stream模塊代理并開啟日志配置

前言 nginx 1.20.1 nginx從1.9.0開始,新增加了一個stream模塊 確保nginx 安裝時開啟stream模塊 ./configure \ …… \ --with-stream \ --with-stream_ssl_module \ 修改nginx.conf #增加stream配置&#xff0c;開啟stream模塊 stream {log_format basic $remote_addr [$…

stm32 作為從機, fpga 作為主機,進行 spi 通信

stm32 作為從機, fpga 作為主機,進行 spi 通信 STM32和FPGA之間的SPI通信是直連形式。使用FPGA讀取傳感器的值,傳輸到STM32中進行計算。 STM32是將SPI接受過來的數據存儲到DMA中。 #include "SPI_DMA.h" #include <stm32f10x.h> uint8_t spi_buf[4];//FP…

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;除此之外&…

前端canvas項目實戰——在線圖文編輯器:序

目錄 前言一、 博主是誰&#xff1f;二、 關于本專欄1. 本專欄涉及的技術棧2. 專欄適合誰來學習&#xff1f;3. 你可以從專欄學到什么&#xff1f;4. 系列文章索引 三、 付費信息后記 前言 很高興&#xff0c;今天我又為自己設定了一個目標&#xff1a;帶領大家從入門HTML5中的…