Spring Security前置知识2--域与跨域

本文深入解析了跨域的概念,包括域的定义、域名的作用及其划分方式,重点阐述了跨域访问的原理及解决方法,如CORS、JSONP和PostMessage等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、结论

  1. 域、跨域都和IP关系不大,和域名有关。
  2. 域名并不是真正的域名
  3. 跨域严格上说是跨源

二、什么是域 Domain

  百度百科的解释
  域是一个网络应用的范围,在这个范围内的用户有一定的访问权限网络内用户或者主机,而不在域中的用户会受到域权限的控制而不能访问一些东西,也就是提升了局域网安全性的一个措施。
简单说,是一种安全策略,将计算机分组,同域的计算机,可以有一定的访问权限。不同域的计算机,会受到访问限制。

三、什么是域名

  我们使用域名来代表(管理)ip地址,使用域名来划分域。
  一开始只有ip地址,ip地址一串纯数字太难记,便设计了域名用来代表ip的这一串数字,方便识别与记忆。网络中有一系列叫做域名系统(DNS Domain Name System)的系统,里面记录有域名和ip的对应关系。通过域名访问某个站点时,会先经过域名系统,将域名解析成ip地址,再进行路由。
  一个域名可以指向多个ip(负载均衡),不同的域名也可能指向同一个ip地址,属于多对多的关系,所以我们上面使用了代表和管理两个词。

1、如何划分域

  ip用来路由,域名用来区分域。
  在只有ip的时候,通过将ip划分到域(类似分组)的方式来划分域,现在windows操作系统里面仍然可以这样分。在有了域名之后,直接通过域名来划分域。
  ip地址的数字主要用来路由,规定了每一位0-255,使用4位数字,以至于6位数字的组合来给每一台机器编号进行路由组网。而域名不需要用来路由,可以随意设置,有无限种可能,你起多长的名字都可以。
  理论上只要一位就可以区分域名,但是为了管理方便,组织方便,仍然使用多级方式表示域名。这便是我们经常听到的顶级域名、一级域名、二级域名、三级域名之类的。

2、域名与hostname

  还有个很有意思的事情是,事实我们把类似www.baidu.com叫做域名是不对的, 在维基百科的定义里,www不属于域名,加不加无所谓,baidu和com两个都算是域名(两个域名),com是一级域名,baidu是二级域名。www.baidu.com或者baidu.com合起来叫做hostname,但是后来我们都管整个hostname叫做域名。。。

四、跨域

  按照上面的描述继续往下推,跨域就是两台域名不同的机器相互访问。
  事实上并不是这样,跨域只是我们的叫法而已,我们在跨域的时候,打开F12,提示的是如下信息
在这里插入图片描述
  这里面并没有出现任何域(domain)这样的字眼,而是Origin。跨域事实上应该叫做跨源Cross Origin。

1、什么是源,什么是跨源(域)

1)一次跨域过程的跟踪

  我们先来追一下跨域的过程,来理解什么到底时候发生了跨域访问
  我们再看上面图片的提示
在这里插入图片描述

  1. 我们从localhost:8080向localhost:8081去请求/test路径下的资源(不论是某个页面还是图片,ajax等)
  2. 我们事实上已经请求到了/test的资源。
    在这里插入图片描述
  3. 8081服务把资源返回出来,交给浏览器,浏览器准备让localhost:8080去访问这个资源。
  4. 这个时候浏览器发现页面不同源,且返回资源的header中的Access-Control-Allow-Origin列表中并没有http://localhost:8080。于是对资源的继续访问被阻止了(been blocked),并抛出异常。

2、同源策略 (SOP Same Origin Policy)

  关于同源策略,百度百科解释的稀烂,还那么短,有兴趣可以去查一查恶心一下自己。去维基或者MDN上看一下。

1)什么是同源策略

  同源是指http请求发起侧和响应侧的协议、域名、端口全部相同(源 = 协议 + 域名 + 端口),其中任意一个不同就是跨源。
  默认情况下,浏览器不允许跨源的访问。

2)为什么需要同源策略

  主要是为了安全,保护网站内部资源,包括iframe,XMLHttpRequest(Ajax)、cookie、localstorage等。具体的展开我们在Web前端攻击篇再说。

关于为什么叫做跨域的猜测
  那个时候可能并没有https,网站协议都是http,端口也是默认的80端口。这个时候,事实上导致“源”不同的,只有域名,跨域==跨源。
  上面纯属个人猜测。

3)如何控制同源策略

  浏览器自动检测是否同源,并严格执行同源策略。其中协议和端口无法控制,但是可以通过document.domain="xxx.xxx"来改变domain。这个改变是有规则的,考虑到www对理解的干扰,我们使用pan.baidu.com做例子,F12敲一下如下代码。
在这里插入图片描述
  1. 提示说我们设置的"abc.com"不是“pan.baidu.com"的后缀。
  2. 提示不能是一级域名。
  也就是必须设置为当前网站的后缀,并且不能是一级域名,其实就是父域。
  由于Cookie、Web Storage等都是基于domain(origin)收集的,修改domain行为也将会影响这些信息的收集。

a) CORS

浏览器严格执行同源策略,但是跨域是实际存在的业务需求。
  怎么办?于是开了一个口子,叫做CORS(Cross-Origin Resource Sharing),跨源资源共享。
  简单说,允许有条件的进行跨源访问,“”有条件“”具体表现为在header里面准备了三个Access-Control-Allow-XXX的属性,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers,分别定义允许的请求来源、方法和头信息,只要请求同时满足这三个条件,则可以访问。
”简单请求“与”预检请求“
  对于请求,按照请求方法和头信息,区分为”简单请求“与”预检请求“。
  对于简单请求和预检请求具体是什么,详细内容自己到MDN上看。https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
  MDN上的回答
  ”对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。"
  “简单请求”,比如查询请求并不会对服务器造成什么副作用*,所以查询接口事实上会执行,在返回之后才判断是  否跨源,我们上面的例子,使用的就是简单的GET请求。
  “预检请求”,比如增删改操作,或者一些搭配特殊头部信息的请求,可能会对服务器造成副作用,不可以先执行再判断,或者从效率上处理起来可能比较复杂。需要“预检”一下。

五、如何解决跨域

1、CORS

  按照上面的描述,双方根据请求方法、资源做好约定,应答方在header中添加合适的Access-Control-Allow-XXX。这是最正统,最安全的解决跨域的手段。

2、JSONP

  简单说,同源策略不限制src、href属性,我们可以随便创建一个带有src属性的元素,如script,img,或者link标签(href),将src/href指向要访问的地址,并带上对返回值进行处理的方法名,比如叫做myCallback。
  这个地址发出去,就相当于一个get方法,目标服务器端执行了这个请求,将查询结果打成json,和方法名拼起来,变成myCallback({params}),请求端解析并执行这个方法,就达到了跨域请求的目的。

1)为什么叫做JSONP

  Json With PaddingJson With Padding,返回一串Json,Padding(Prefix)了一个方法名。

2)CORS与JSONP对比

  1. JSONP是在CORS没有出来之前,绕过同源策略的一种方法。
  2. 而CORS是比较正统的解决方案。
  3. JSONP只支持GET,但是跨域请求一般也不太会用其它方式(因为往往都是跨域查询),GET足以应付大部分场景。如果需要对服务端资源进行操作,使用CORS。
  4. 如果需要兼容低版本的IE浏览器(IE8之前),需要使用JSONP。
  5. 从安全上讲,肯定是CORS更强。

3、PostMessage

  H5的PostMessage,用于不同页面间的消息传递,同样也可以用于不同域的页面间的消息通信。可以先页面间通信,页面再与后端通信,也能达到跨域的目的。

<think>嗯,用户想了解如何使用Spring Boot 3.2.5和Spring Security 6.2.4实现微信登录。首先,我得理清楚微信登录的流程。微信OAuth2.0的流程一般是前端引导用户跳转到微信的授权页面,用户意后,微信会返回一个code,后端用这个code去换access_token和openid,然后获取用户信息。 接下来,需要考虑Spring Security的OAuth2客户端配置。Spring Security 6.x之后,OAuth2的配置方式可能有变化,特别是从旧的spring-security-oauth2迁移到了新的支持方式。需要确认Spring Security 6.2.4是否支持OAuth2客户端的配置,以及如何配置。 首先,用户需要注册微信开放平台的应用,获取AppID和AppSecret,这是必须的。然后在Spring Boot项目中添加相关依赖,比如spring-boot-starter-oauth2-client,这个应该包含了Spring Security的OAuth2客户端支持。 然后,配置application.yml或者application.properties,设置微信的客户端配置,包括client-id、client-secret、授权范围、重定向URI等。微信的授权端点可能和标准的OAuth2有所不,需要找到正确的authorization-uri和token-uri,比如微信的授权URL是https://open.weixin.qq.com/connect/qrconnect,token URL是https://api.weixin.qq.com/sns/oauth2/access_token。 接下来,可能需要自定义一些组件,因为微信的响应格式可能不符合Spring Security的默认处理。例如,用户信息的端点返回的数据结构可能不,需要自定义一个UserService来解析微信返回的用户信息,并转换为Spring Security的UserDetails对象。 另外,Spring Security默认的登录页面可能需要调整,或者需要配置自定义的登录页面,引导用户跳转到微信登录。或者使用前端的处理方式,比如在前端生成微信登录的链接,用户点击后跳转,后端处理回调。 还有,微信的OAuth2流程中,获取用户信息可能需要access_token和openid,所以在获取token之后,还需要调用微信的用户信息接口,比如https://api.weixin.qq.com/sns/userinfo。 在Spring Security中,可能需要实现一个OAuth2UserService接口,覆盖默认的加载用户流程,处理微信返回的数据。时,用户信息可能需要保存到数据库中,或者直接使用微信的信息进行认证。 另外,问题需要注意,特别是前端和后端分离的情况下,需要配置CORS。时,安全配置需要允许OAuth2的相关端点,比如/oauth2/authorization/weixin,以及回调的路径,比如/login/oauth2/code/weixin。 还需要考虑用户登录后的处理,比如生成JWT令牌,或者跳转到前端页面,保存用户会话等。如果使用JWT,可能需要配置Spring Security的过滤器链,添加JWT生成和验证的过滤器。 测试过程中,可能需要使用内网穿透工具,因为微信的回调需要公网可访问的名,开发时可以用ngrok或者localhost.run来暴露本地服务。 可能遇到的坑包括:微信的授权名需要正确配置,回调地址必须在微信开放平台中设置;Spring Security的客户端注册ID需要和配置中的一致;微信返回的字段名可能和Spring Security默认的不,需要自定义映射;还有可能因为版本问题,某些配置方式已经过时,需要查阅最新的文档。 最后,需要确保依赖的版本兼容性,Spring Boot 3.2.5对应的Spring Security版本是6.2.x,所以应该没问题。时,要注意依赖管理,避免版本冲突。 总结下来,步骤大概是:注册微信应用,配置Spring Security的OAuth2客户端,自定义用户信息处理,处理回调,配置安全策略,测试整个流程。可能需要参考Spring Security和微信的官方文档,确保各个参数正确无误。</think>以下是使用Spring Boot 3.2.5和Spring Security 6.2.4实现微信登录的主要步骤: ### 一、前置准备 1. **注册微信开放平台** - 创建网站应用,获取`AppID`和`AppSecret` - 设置授权回调(如`www.yourdomain.com`) 2. **添加依赖** ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> ``` ### 二、配置Spring Security ```yaml # application.yml spring: security: oauth2: client: registration: weixin: client-id: your_appid client-secret: your_appsecret authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/weixin" scope: snsapi_login client-name: Weixin provider: weixin: authorization-uri: https://open.weixin.qq.com/connect/qrconnect token-uri: https://api.weixin.qq.com/sns/oauth2/access_token user-info-uri: https://api.weixin.qq.com/sns/userinfo user-name-attribute: openid ``` ### 三、自定义用户服务 ```java @Component public class WeixinOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // 获取access_token OAuth2AccessToken accessToken = userRequest.getAccessToken(); // 调用微信API获取用户信息 String userInfoUrl = userRequest.getClientRegistration() .getProviderDetails().getUserInfoEndpoint().getUri(); userInfoUrl += "?access_token=" + accessToken.getTokenValue() + "&openid=" + ((DefaultOAuth2AccessToken)accessToken).getAdditionalParameters().get("openid"); // 解析微信返回的JSON数据 RestTemplate restTemplate = new RestTemplate(); Map<String, Object> userAttributes = restTemplate.getForObject(userInfoUrl, Map.class); return new DefaultOAuth2User( Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")), userAttributes, "openid" // 对应微信返回的用户标识字段 ); } } ``` ### 四、安全配置 ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private WeixinOAuth2UserService weixinOAuth2UserService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/", "/login**").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .userInfoEndpoint(userInfo -> userInfo .userService(weixinOAuth2UserService) ) .defaultSuccessUrl("/userinfo", true) ) .csrf(csrf -> csrf.disable()); return http.build(); } } ``` ### 五、控制器示例 ```java @RestController public class UserController { @GetMapping("/userinfo") public Map<String, Object> userInfo(OAuth2User principal) { return principal.getAttributes(); // 返回微信用户信息 } } ``` ### 六、注意事项 1. **名验证** - 必须使用备案- 微信回调地址需注册时一致 2. **Session管理** - 建议配置Redis实现分布式Session ```yaml spring: session: store-type: redis timeout: 3600 ``` 3. **安全增强** - 建议添加CSRF保护 - 启用HTTPS ### 七、测试流程 1. 访问 `http://localhost:8080/oauth2/authorization/weixin` 2. 跳转至微信登录页面 3. 用户授权后自动回调到 `/userinfo` 接口 ### 常见问题处理 1. **`redirect_uri`参数错误** - 检查微信开放平台配置的授权- 确保回调地址完整匹配 2. **获取用户信息为空** - 确认`scope`设置为`snsapi_login` - 检查access_token是否有效 3. **问题** ```java @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("https://your-frontend-domain")); config.setAllowedMethods(Arrays.asList("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } ``` 以上方案基于Spring Security的OAuth2客户端实现,如需更复杂的业务逻辑(如自动注册本地用户),可在`WeixinOAuth2UserService`中添加数据库操作逻辑。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值