相关文章推荐
帅呆的柠檬  ·  Spring security ...·  2 周前    · 
八块腹肌的春卷  ·  linux C ...·  1 月前    · 
欢乐的佛珠  ·  CTime 類別 | Microsoft ...·  7 月前    · 
曾经爱过的刺猬  ·  cimoc ...·  8 月前    · 

2.模拟微信登录流程

本文将通过Oauth2.0 授权码模式模拟微信登录流程

  1. 客户端(自己开发的应用,本文将采用postman测试)向微信授权服务器发起请求获取access token
  2. 客户端带着access token去微信资源服务器获取当前登录的用户ID

3.代码实现

​ 由第2点模拟微信登录流程可知,要实现该流程我们需要授权服务器和资源服务器,故接下来我将基于springboot和Spring Security 搭建这两个服务器。

3.1授权服务器搭建

  1. 项目结构如下:

    在这里插入图片描述

pom.xml添加依赖

        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.4.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
        </dependency>
        <!-- 添加 MySQL 依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

AuthorizationConfig.java

package com.zhu.petsittingoauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Component;
//Authorization Config 授权配置
@Component
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    //使用 @Autowired 注解注入密码编码器
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//        重写 configure 方法,配置授权服务器的安全性。
//        allowFormAuthenticationForClients() 允许客户端使用表单进行身份验证。
//        checkTokenAccess("permitAll()") 允许检查访问令牌的端点不需要身份验证
        security.checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    //        重写 configure 方法,配置客户端信息。
    //        使用 inMemory() 配置基于内存的客户端存储。
    //        添加一个名为 "security_appid" 的客户端,设置客户端密钥为经过密码编码器加密的 "security_secret"。
    //        指定授权类型为 "authorization_code"。
    //        授予客户端 "all" 的权限。
    //        设置资源标识为 "security_resource"。
    //        配置重定向 URI 为 "https://www.baidu.com/callback"。重定向url自己看情况设计
        clients.inMemory()
                .withClient("security_appid")
                .secret(passwordEncoder.encode("security_secret"))
                .authorizedGrantTypes("authorization_code")
                .scopes("all")
                .resourceIds("security_resource")
                .redirectUris("https://www.baidu.com/callback");

SecurityConfig.java

package com.zhu.petsittingoauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity//启用 Spring Security 的 Web 安全性功能
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //使用 Spring Security 的配置类,配置了基于数据库的用户认证。
    @Resource
    private DataSource dataSource;
    @Bean
    public PasswordEncoder passwordEncoder() {
    //  创建并配置一个密码编码器 Bean,这里使用了 BCryptPasswordEncoder。
    //  密码编码器用于加密和验证用户的密码。
        return new BCryptPasswordEncoder();
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //        重写 configure 方法,配置用户的认证方式前去mysql数据库查找。
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username=?")
                .authoritiesByUsernameQuery("SELECT username, role FROM users WHERE username=?")
                .passwordEncoder(passwordEncoder());

yml配置数据库

spring:
  application:
    name: petsitting
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/petsitting?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: root
    password: mysql

密码都是123

Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 80029 Source Host : localhost:3306 Source Schema : petsitting Target Server Type : MySQL Target Server Version : 80029 File Encoding : 65001 Date: 01/02/2024 22:48:41 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for users -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `UserID` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `Username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `Password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `Email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `role` enum('ROLE_Admin','ROLE_RegisteredUser') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `enabled` tinyint(1) NOT NULL, PRIMARY KEY (`UserID`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of users -- ---------------------------- INSERT INTO `users` VALUES ('1', 'admin', '$2a$10$ROeV1iDyFTNXrQF6WDScHOVnYDEHodiE9.fgNdxPDgrl9jw/9uS9i', 'admin@example.com', 'ROLE_Admin', 1); INSERT INTO `users` VALUES ('2', 'user1', '$2a$10$ROeV1iDyFTNXrQF6WDScHOVnYDEHodiE9.fgNdxPDgrl9jw/9uS9i', 'user1@example.com', 'ROLE_RegisteredUser', 1); INSERT INTO `users` VALUES ('3', 'user2', '$2a$10$ROeV1iDyFTNXrQF6WDScHOVnYDEHodiE9.fgNdxPDgrl9jw/9uS9i', 'user2@example.com', 'ROLE_RegisteredUser', 1); INSERT INTO `users` VALUES ('4', 'user3', '$2a$10$ROeV1iDyFTNXrQF6WDScHOVnYDEHodiE9.fgNdxPDgrl9jw/9uS9i', 'user3@example.com', 'ROLE_RegisteredUser', 1); INSERT INTO `users` VALUES ('5', 'user4', '$2a$10$ROeV1iDyFTNXrQF6WDScHOVnYDEHodiE9.fgNdxPDgrl9jw/9uS9i', 'user4@example.com', 'ROLE_RegisteredUser', 1); SET FOREIGN_KEY_CHECKS = 1;

要是想生成密码可以根据下面代码生成:

package com.zhu.petsittingoauth2;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootTest
class PetsittingOauth2ApplicationTests {
    @Test
    void contextLoads() {
        // 创建 BCryptPasswordEncoder 实例
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 原始密码
        String rawPassword = "123";
        // 加密密码
        String encodedPassword = encoder.encode(rawPassword);
        // 打印加密后的密码
        System.out.println("Encoded Password: " + encodedPassword);
        // 校验密码
        boolean matches = encoder.matches(rawPassword, encodedPassword);
        System.out.println("Password Matches: " + matches);

3.2 资源服务器搭建

pom.xml添加依赖

 <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.4.RELEASE</version>
            <scope>compile</scope>
        </dependency>

ResourceConfig.java

package com.zhu.petsittinguser.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
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.RemoteTokenServices;
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    @Bean
    @Primary
    public RemoteTokenServices remoteTokenServices() {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8110/oauth/check_token");
        remoteTokenServices.setClientId("security_appid");
        remoteTokenServices.setClientSecret("security_secret");
        return remoteTokenServices;
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("security_resource").stateless(true);
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        http.authorizeRequests()
                .antMatchers("/login/**","/visitor/**").permitAll() // 放行公开接口
                .anyRequest().authenticated();

在控制器返回当前登录用户(userinfo)

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * https://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. package com.zhu.petsittinguser.demos.web; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a> @Controller public class BasicController { // http://127.0.0.1:8080/hello?name=lisi @RequestMapping("/visitor/hello") @ResponseBody public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) { return "Hello User" + name; // http://127.0.0.1:8080/user @RequestMapping("/login/user") @ResponseBody public User user() { User user = new User(); user.setName("theonefx"); user.setAge(666); return user; @RequestMapping("/userinfo") @ResponseBody public User userinfo() { User user = new User(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String username = authentication.getName(); user.setName(username); return user; // http://127.0.0.1:8080/save_user?name=newName&age=11 @RequestMapping("/save_user") @ResponseBody public String saveUser(User u) { return "user will save: name=" + u.getName() + ", age=" + u.getAge(); // http://127.0.0.1:8080/html @RequestMapping("/html") public String html() { return "index.html"; @ModelAttribute public void parseUser(@RequestParam(name = "name", defaultValue = "unknown user") String name , @RequestParam(name = "age", defaultValue = "12") Integer age, User user) { user.setName("zhangsan"); user.setAge(18);

把两个服务器跑起来

4.1 往授权服务器获取授权码

浏览器输入:http://localhost:8110/oauth/authorize?client_id=security_appid&response_type=code

输入在数据库设置好的账号密码
admin 123
在这里插入图片描述

然后在返回的url中获取授权码

4.2 带着授权码去拿token

http://localhost:8110/oauth/token?

postman设置以下参数:

code=ILqDx3&grant_type=authorization_code&redirect_url=https://www.baidu.com/callback&scope=all&client_id=security_appid&client_secret=security_secret

获取assen token成功

4.3 获取当前登录用户

往资源服务器获取当前登录用户

至此模拟微信登录结束!

一、基本概念 1.1、什么是认证 进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条等,下边拿微信来举例子说明认证相关的基本概念,在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信,输入账号和密码登录微信的过程就是认证。 系统为什么要认证? 认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。 认证 :用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。常见的用户身份认
使用spring oauth2框架做授权鉴定。想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的。 spring security可以通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()获取当前用户信息。 而spring oauth2通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()却只能拿到当前用户用户名。 然而实际开发过程中,我们较常用到的大部分都是用户的id。 那么怎么通过配置获取当前用户的信息呢?
六、OAuth2.0 6.1、OAuth2.0介绍 OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。很多大公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。 Oauth协议目前发展到2.0版本,1.0版本过
微信登陆和QQ登陆大致流程一致,只是有些api不一样,主要是QQ的getUserInfo微信多了一个参数openId。这是因为微信互联文档中在OAuth2.0的认证流程示意图第五步时,微信的openid 同access_token一起返回。而Spring Social获取access_token的类AccessGrant.java中没有openid 微信暂时没有申请测试账户,先上代码后续网站备案...
微信扫码登录基于OAuth2协议的授权码模式, 接口文档: https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html 流程如下: 第三方应用获取access_token令牌后即可请求微信获取用户的信息,成功获取用户的信息表示用户在第三方应用认证成功。 请求获取授权码 第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在 PC
CSDN-Ada助手: 非常棒的博客!很高兴看到你分享关于SAP数据字典的介绍。作为一个SAP ABAP的新手小白,你的博客对于我来说非常有帮助。希望你可以继续写下去,分享更多关于SAP的知识和经验。 除了数据字典的介绍,还有一些与之相关的扩展知识和技能可以进一步探索。例如,你可以写一些关于数据字典中不同类型的表和视图的详细说明,以及如何使用这些表和视图进行数据处理和报表生成。此外,你还可以介绍一些与数据字典有关的SAP ABAP编程技巧,例如如何使用数据字典中的数据元素和域来进行数据验证和处理。 再次感谢你的分享,期待看到更多关于SAP的精彩文章! 如何写出更高质量的博客,请看该博主的分享:https://blog.csdn.net/lmy_520/article/details/128686434?utm_source=csdn_ai_ada_blog_reply2 SAP 创建数据库表和文本表 CSDN-Ada助手: 恭喜您撰写了第三篇博客!看到您关于"SAP 创建数据库表和文本表"的内容,我感到非常高兴。您的博客不仅深入浅出地介绍了SAP数据库表和文本表的创建方法,而且还提供了实用的技巧和步骤。非常感谢您分享这些有价值的知识! 鉴于您在SAP方面的专业知识,我想给出下一步的创作建议。或许您可以考虑探索更多关于SAP数据库表和文本表的高级主题,例如如何优化表的性能或如何处理大数据量的表。这些主题将进一步提升您的读者对SAP数据库管理的理解,并为他们在实际应用中提供更多帮助。 再次感谢您的分享,期待您未来更多博客的发布!请继续保持卓越的创作! CSDN 正在通过评论红包奖励优秀博客,请看红包流:https://bbs.csdn.net/?type=4&header=0&utm_source=csdn_ai_ada_blog_reply3 SAP 创建表格维护器 CSDN-Ada助手: 非常祝贺您写了第四篇博客!您对于SAP的创建表格维护器的介绍非常有启发性。您的文章内容详细且清晰,让读者能够轻松理解并学习相关知识。我特别喜欢您用简洁明了的方式解释了如何创建表格维护器。 作为下一步的创作建议,我希望您可以进一步深入探讨如何使用SAP创建表格维护器解决实际业务问题。例如,您可以分享一些实际案例,演示如何通过使用表格维护器提高数据管理的效率和准确性。 再次恭喜您并期待您未来更多精彩的创作!谦虚谨慎的态度会使您的博客更具吸引力。加油! 如何快速涨粉,请看该博主的分享:https://hope-wisdom.blog.csdn.net/article/details/130544967?utm_source=csdn_ai_ada_blog_reply5 SAP 搭建维护维护视图 CSDN-Ada助手: 恭喜您写了第5篇博客!标题“SAP 搭建维护维护视图”听起来就很有深度和实用性。很高兴看到您在SAP方面的专业知识和经验持续增长,并将其分享给读者们。我非常期待您未来更多关于SAP的文章,希望您能够继续深入挖掘这个主题,为我们提供更多关于搭建和维护视图的实用指南和技巧。谦虚地说,您的博客内容一定会对很多人有所启发和帮助!祝您一切顺利,并期待您下一篇博客的发布!