前言
目前正在出一个SpringCloud进阶
系列教程,含源码解读
, 篇幅会较多, 喜欢的话,给个关注❤️ ~
前段时间拖更了,主要事情比较多和杂,不多废话了,直接给大家开整吧~ 本节重点是给大家介绍Oauth2,将会带大家从0到1搭建一个 SpringCloud
项目,以及整合Oauth2 Server
,实现基本的授权和认证功能。
什么是OAuth2.0
跟往常一样,在学习新知识前,首先明白它是啥?
我相信大部分人应该都对它都有了解,甚至使用过。如果你没有亲自搭建过这样的服务,但是在对接第三方平台的时候,首先需要去进行服务认证,在大多数的认证服务中,很多都是基于OAuth2.0
的。
首先我们需要明白这样一个概念, OAuth
,它是一个授权(Authorization)的开放标准,大家都可以基于这个标准去实现。OAuth基于HTTPS,以及APIs,Service应用使用```access_token````来进行身份验证。
它主要有OAuth 1.0
和OAuth 2.0
,二者不兼容。OAuth2.0 是目前广泛使用的版本,大部分说的OAuth
都是OAuth2.0
基本流程
它的基本流程是怎么样的呢?我们先看张图
上图中所涉及到的对象分别为:
Client
第三方应用,我们的应用就是一个ClientResource Owner
资源所有者,即用户Authorization Server
授权服务器,即提供第三方登录服务的服务器,如GithubResource Server
拥有资源信息的服务器,通常和授权服务器属于同一应用
根据上图的信息,我们可以知道OAuth2
的基本流程为:
- 第三方应用请求用户授权。
- 用户同意授权,并返回一个凭证
(code)
- 第三方应用通过第二步的凭证
(code)
向授权服务器请求授权 - 授权服务器验证凭证
(code)
通过后,同意授权,并返回一个资源访问的凭证(Access Token)
。 - 第三方应用通过第四步的凭证
(Access Token)
向资源服务器请求相关资源。 - 资源服务器验证凭证
(Access Token)
通过后,将第三方应用请求的资源返回。
基本概念就介绍到这里,下面我们就一起整一下吧~
基本项目框架搭建
首先我们的准备工作,需要安装好Nacos
,如果还不会的同学可以参考我之前写的文章,这里默认大家都安装好了。本节呢,我们统一给大家尝试高版本,我这里的SpringBoot
版本是2.6+
,SpringCloud
是2021
,基本上都是比较新的版本了
下面新建一个maven
项目,父工程的pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pkq-cloud</groupId> <artifactId>com.pkq.cloud</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>spring-cloud-oauth2-server</module> </modules> <packaging>pom</packaging> <properties> <fate.project.version>1.0.0</fate.project.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <maven.plugin.version>3.8.1</maven.plugin.version> <spring.boot.version>2.6.3</spring.boot.version> <spring-cloud.version>2021.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version> <alibaba.nacos.version>1.4.2</alibaba.nacos.version> <alibaba.sentinel.version>1.8.3</alibaba.sentinel.version> <alibaba.dubbo.version>2.7.15</alibaba.dubbo.version> <alibaba.rocketMq.version>4.9.2</alibaba.rocketMq.version> <alibaba.seata.version>1.4.2</alibaba.seata.version> <mybatis.plus.version>3.5.1</mybatis.plus.version> <knife4j.version>3.0.2</knife4j.version> <swagger.version>3.0.0</swagger.version> </properties> <dependencyManagement> <dependencies> <!-- springBoot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- springCloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies> </project> 复制代码
大家可以直接复制过去,下面我们新建一个模块叫spring-cloud-oauth2-server
,这个模块就是OAuth2
的授权服务中心,看下它的pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>com.pkq.cloud</artifactId> <groupId>pkq-cloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>spring-cloud-oauth2-server</artifactId> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--SpringBoot2.4.x之后默认不加载bootstrap.yml文件,需要在pom里加上依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <!-- Nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <exclusions> <exclusion> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </exclusion> </exclusions> <version>${spring-cloud-alibaba.version}</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <exclusions> <exclusion> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </exclusion> </exclusions> <version>${spring-cloud-alibaba.version}</version> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>${alibaba.nacos.version}</version> </dependency> <!-- Druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.22</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!-- MyBatis-Plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis.plus.version}</version> </dependency> <!-- redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>9.9.3</version> </dependency> <!--security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.0</version> </dependency> <!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> </project> 复制代码
该模块下的配置文件bootstrap.yml
,不知道啥是bootstrap
配置文件的可以参考我之前的文章,在讲Nacos
的时候有给大家讲
server: port: 10001 spring: application: name: oauth2-server datasource: url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: ******** driver-class-name: com.mysql.cj.jdbc.Driver redis: host: 127.0.0.1 port: 6379 database: 2 cloud: nacos: discovery: #注册中心地址 server-addr: 127.0.0.1:8848 config: file-extension: yaml #配置中心地址 server-addr: 127.0.0.1:8848 thymeleaf: cache: false mybatis-plus: mapper-locations: classpath:mapper/*/*.xml,mapper/*.xml global-config: db-config: id-type: auto field-strategy: NOT_EMPTY db-type: MYSQL configuration: map-underscore-to-camel-case: true call-setters-on-nulls: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 复制代码
这里为了方便演示,直接把配置写到文件了,也可以放到Nacos
配置中心里,这里主要是当服务注册中心使用, Nacos
用到的sql
我放到项目的db
目录下了,需要的可自行获取
下面我们加个启动类,看是否启动正常~
/** * @Author * @Description 启动类 * @Date */ // @SpringCloudApplication 被弃用 @SpringBootApplication public class OauthServerApplication { public static void main(String[] args) { SpringApplication.run(OauthServerApplication.class, args); } } 复制代码
在新版本中@SpringCloudApplication
被弃用了,我们直接使用@SpringBootApplication
就好了,你会发现,啥都不加服务也会自动注册,说明新版本中已经比较完善了。@SpringCloudApplication
本质上也就是在@SpringBootApplicaiton
中加了几个注解
@Deprecated @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootApplication @EnableDiscoveryClient public @interface SpringCloudApplication { } 复制代码
启动一下,如果正常说明第一步我们就成功了~ 下面我们进入正题
搭建 OAuth2 Server
首先我们要去搭建一个认证服务配置
,Oauth2有多种模式,常见的有密码模式
还有授权码模式
,现在比较流行的就是授权码模式
,下面要带大家实现的就是基于授权码模式
的
认证服务配置
/** * @Author qcl * @Description Oauth2 认证服务配置 * @Date */ @AllArgsConstructor @Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter { // 认证管理器 @Autowired private AuthenticationManager authenticationManager; // 数据源 @Autowired private DataSource dataSource; //密码加密方式 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 自定义身份认证 @Autowired private UserServiceImpl userDetailsService; @Bean public ClientDetailsService jdbcClientDetailsService(){ //存储client信息 return new JdbcClientDetailsService(dataSource); } @Bean public TokenStore tokenStore(){ // token存储 return new JdbcTokenStore(dataSource); } @Bean public AuthorizationCodeServices authorizationCodeServices() { // 授权码模式 return new JdbcAuthorizationCodeServices(dataSource); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { //配置 client信息从数据库中取 clients.withClientDetails(jdbcClientDetailsService()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore())//token存储方式 .authenticationManager(authenticationManager)// 开启密码验证,由 WebSecurityConfigurerAdapter .userDetailsService(userDetailsService)// 读取验证用户信息 .authorizationCodeServices(authorizationCodeServices()) .setClientDetailsService(jdbcClientDetailsService()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 配置Endpoint,允许请求 security.tokenKeyAccess("permitAll()") // 开启/oauth/token_key 验证端口-无权限 .checkTokenAccess("isAuthenticated()") // 开启/oauth/check_token 验证端口-需权限 .allowFormAuthenticationForClients()// 允许表单认证 .passwordEncoder(passwordEncoder()); // 配置BCrypt加密 } } 复制代码
这里我们使用基于持久化
的配置,相关注释已经加上了,那么它的数据存在哪呢?它是存在数据库中,下面我们需要准备几张表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for oauth_access_token -- ---------------------------- DROP TABLE IF EXISTS `oauth_access_token`; CREATE TABLE `oauth_access_token` ( `token_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `token` blob NULL, `authentication_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `client_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `authentication` blob NULL, `refresh_token` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL ) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '存储生成的access_token' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of oauth_access_token -- ---------------------------- -- ---------------------------- -- Table structure for oauth_client_details -- ---------------------------- DROP TABLE IF EXISTS `oauth_client_details`; CREATE TABLE `oauth_client_details` ( `client_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, `resource_ids` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `client_secret` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `scope` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `authorized_grant_types` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `web_server_redirect_uri` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `authorities` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `access_token_validity` int NULL DEFAULT NULL, `refresh_token_validity` int NULL DEFAULT NULL, `additional_information` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL, `autoapprove` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'false', PRIMARY KEY (`client_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '存储客户端的配置信息' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of oauth_client_details -- ---------------------------- INSERT INTO `oauth_client_details` VALUES ('clientId1', '1', '$2a$10$WFDhpNunaH0aPlPQp33q8OAlqot6NANran7HeP/DSSWt1kVRvF2d2', 'all', 'password,refresh_token,authorization_code,implicit,client_credentials', 'https://www.baidu.com', 'ROLE_ADMIN', 604800, 1209600, '{\"info\": \"test\"}', 'false'); -- ---------------------------- -- Table structure for oauth_code -- ---------------------------- DROP TABLE IF EXISTS `oauth_code`; CREATE TABLE `oauth_code` ( `code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `authentication` blob NULL ) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '存储服务端系统生成的code的值' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for oauth_refresh_token -- ---------------------------- DROP TABLE IF EXISTS `oauth_refresh_token`; CREATE TABLE `oauth_refresh_token` ( `token_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, `token` blob NULL, `authentication` blob NULL ) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '存储刷新令牌的refresh_token' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of oauth_refresh_token -- ---------------------------- SET FOREIGN_KEY_CHECKS = 1; 复制代码
默认给大家已经插入了一条客户端的配置,后边我们会用到它
在代码中,我们可以看到导入了一个UserDetailsService
,这个类需要我们实现它
/** * @Author qcl * @Description 用户信息 * @Date */ @Slf4j @Service public class UserServiceImpl implements UserDetailsService { @Autowired private SysUserService sysUserService; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { UserInfo userInfo = sysUserService.getUserByUserName(userName); log.warn("user: " + userInfo.getUsername()); if (userInfo == null){ throw new UsernameNotFoundException("用户不存在: " + userName); } List<GrantedAuthority> authorities=new ArrayList<>(); //获取用户权限 List<String> permissions = userInfo.getPermissions(); permissions.forEach(permission->{ authorities.add(new SimpleGrantedAuthority("ROLE_" + permission)); }); // 这里一定要基于 BCrypt 加密,不然会不通过 UserDetails user = new User(userInfo.getUsername(), new BCryptPasswordEncoder().encode(userInfo.getPassword()), authorities); log.warn(user.toString()); return user; } } 复制代码
它主要是用来验证和存储用户信息的,场景就是用户在进行登录授权的时候会走到这里边,我们可以在这进行用户身份校验,SysUserService
也是我们自己实现的,用来获取用户信息,这里为了方便演示,直接模拟了
@Service public class SysUserServiceImpl implements SysUserService { @Override public UserInfo getUserByUserName(String userName) { ArrayList<String> list = new ArrayList<>(); list.add("ADMIN"); UserInfo user = new UserInfo(); user.setUserId("1111"); user.setPassword("123321"); user.setUsername(userName); user.setPermissions(list); return user; } } 复制代码
这里给大家提示下可能遇到的坑, 就是userInfo.getPassword()
, 如果你是从数据库读的,如果使用了BCryptPasswordEncoder
加密过的,那么可以,如果不是的话,你就需要BCryptPasswordEncoder
加密一下,不过这样不大安全,推荐是大家在数据库加密,我这里为了方便给大家演示
开启Spring Security配置
下面我们整一下安全配置
/** * @Author * @Description 开启Spring Security配置 * @Date */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/oauth/check_token"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll() .antMatchers("/view/**").permitAll() .anyRequest().authenticated(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } 复制代码
认证流程
现在我们就可以启动它了,然后到浏览器访问http://localhost:10001/oauth/authorize?client_id=clientId1&response_type=code&scope=all&redirect_uri=https://www.baidu.com
有几个参数,给大家解释一下:
/oauth/authorize
这个是Ouath2默认开启的规范接口,通过它进行客户端验证client_id
客户端ID, 也就是分配给第三方的认证ID,response_type=code
返回的类型code,也就是我们开启的是授权码模式scope
授权范围, 需要和我们数据库配置的一致redirect_uri
认证成功后重定向的地址,它会携带code
参数
说了这些,一开始接触的朋友,可能还是不大清除,下面给一张图给大家体会一下:
如果有朋友接过h5微信的登录,相必会深有体会
下面,我们就去访问它。当我们在浏览器输入地址的时候会自动跳转到/login
的地址页面。这个页面是框架自带的,有时候,我们有很多个性化的需求需要自定义,下面就带大家整一下自定义的登录和授权页面
自定义授权和登录页
配置也很简单,我们只需要修改WebSecurityConfig
的配置
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll() .antMatchers("/view/**", "/user/**").permitAll() .anyRequest().authenticated(); http.formLogin() // 自定义处理登录逻辑的地址login .loginProcessingUrl("/login") // 自定义登录页面 .loginPage("/view/login") .permitAll() .and() .csrf().disable().httpBasic(); } 复制代码
这里,我已经准备好了模板,我们使用thymeleaf
简单的给大家演示一下
/** * @Author * @Description * @Date */ @Controller @RequestMapping("/view") public class ViewController { @RequestMapping("/login") public String loginView(Model model) { return "oauth-login"; } } 复制代码
- templates/oauth-login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www/thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <div> <h1>授权登录页</h1> <br/> <form name="loginForm" method="post" action="/login"> 用户名: <input type="text" name="username" placeholder="用户名" /> <br/> 密码: <input type="password" name="password" placeholder="密码" /> <button type="submit">点击登录</button> </form> </div> </body> </html> 复制代码
因为我们引入的是```spring-boot-starter-thymeleaf````,所以默认给我们配置好了,直接添加html就可以了,下面我们再自定义一下授权页,授权页就是比如你用qq登录了网站, 你扫码成功了或者密码输入整个了,这时候会提示获取你的信息,你同意了才可以继续操作
自定义授权页,相对复杂一点,如果对流程和源码不咋熟的话,有点困难
首先需要我们改一下Oauth2ServerConfig
的配置,因为授权在这里
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore())//token存储方式 .authenticationManager(authenticationManager)// 开启密码验证,由 WebSecurityConfigurerAdapter .userDetailsService(userDetailsService)// 读取验证用户信息 .authorizationCodeServices(authorizationCodeServices()) // 自定义授权跳转 .pathMapping("/oauth/confirm_access", "/custom/confirm_access") // 自定义异常跳转 .pathMapping("/oauth/error", "/view/oauth/error") .setClientDetailsService(jdbcClientDetailsService()); } 复制代码
默认下是"/oauth/confirm_access
,我们替换成自定义的/custom/confirm_access
,同样的自定义异常的页面也是可以的。下一步,我们需要加个控制器AuthorizeController
@SessionAttributes("authorizationRequest") @Controller public class AuthorizeController { @RequestMapping("/custom/confirm_access") public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception { AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest"); ModelAndView view = new ModelAndView(); view.setViewName("oauth-authorize"); view.addObject("clientId", authorizationRequest.getClientId()); view.addObject("scopes",authorizationRequest.getScope()); return view; } } 复制代码
紧接着就是模板文件 oauth-authorize.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www/thymeleaf.org"> <head> <meta charset="UTF-8"> <title>授权页</title> </head> <body> <div> <h3 th:text="${clientId}+' 请求授权,该应用将获取你的以下信息'"></h3> <p>昵称,头像和性别</p> 授权后表明你已同意 <a href="#boot" style="color: #E9686B">服务协议</a> <form method="post" action="/oauth/authorize"> <input type="hidden" name="user_oauth_approval" value="true"> <div th:each="item:${scopes}"> <input type="radio" th:name="'scope.'+${item}" value="true" checked>同意 <input type="radio" th:name="'scope.'+${item}" value="false" >拒绝 </div> <input name="authorize" value="同意/授权" type="submit"> </form> </div> </body> </html> 复制代码
这一步,你可以向用户展示信息,这里就给大家简单写写,我们主要体验功能, 好,有了这些准备之后,我们可以正式进入测试环节了
测试环节
首先访问http://localhost:10001/oauth/authorize?client_id=clientId1&response_type=code&scope=all&redirect_uri=https://www.baidu.com
,然后自动跳转到/view/login
,输入完用户名和密码会跳转到授权页
也就是/custom/confirm_access
点击同意之后会跳转到https://www.baidu.com?code=xxx
,会携带code
参数,下面我们就可以通过code
获取access_token
了,获取token````的地址,
http://localhost:10001/oauth/token```,使用```POST```请求,因为我们开启了``` .allowFormAuthenticationForClients()// 允许表单认证```,所以可以进行表单请求,如果没开启的话,是没法的。
我们需要拿着secret
去请求,也就是数据库存储的client_secret
,这个一般由服务提供者提供,也就是所谓的秘钥
成功之后会返回```access_token``,到这里我们就算搭建成功了
说一下这里大家可能遇到的坑,如果你遇到了not like BCrypt
的报错,然后明明你的代码配置都对,可怎么改都没有用,八成是你的secret
不对,首先排查你传的secret
,这个时没有BCrypt
过的,其次就是数据库存储的secret
这里不能明文存储,需要是加密过的,这个也很简单,我们本地加密一下存进去就行了
public class BCryptTest { public static void main(String[] args) { System.out.println(new BCryptPasswordEncoder().encode("123321")); } } 复制代码
结束语
本节到这里就结束了,下节带着大家看一下微服务之间如何统一认证统一鉴权,如何统一管理我们的资源服务,如何加入jwt支持以及整合我们的网关服务。关注我,不迷路 ~