分布式认证中心第一集 引入oauth2授权服务器

📅 2026/6/21 10:05:20
分布式认证中心第一集 引入oauth2授权服务器
前情提要一个“不雅观”的痛点在上一季《Security第十六集引入JWT》中不知道大家有没有发现一个极其尴尬的画面——两个微服务里各自建了一个JwtUtils类各自定义了一模一样的SECRET_KEY还必须确保这俩密钥值完全相同。这画面像什么像极了异地恋情侣非得约定同一句暗号才能确认“是我本人”。代码冗余不说只要密钥一换所有服务都得跟着改改到天荒地老。有同学可能会问“那怎么办总不能让他们一直这么‘异地’下去吧”别急OAuth2 就是来当这个月老的。今天我们就手把手把Security和OAuth2撮合成一对“认证授权CP”让它们分工明确、各司其职彻底终结那段“密钥复制粘贴”的苦日子。第一幕认清各自的本职工作在动手改造之前咱先把职责掰扯清楚免得后面迷糊Spring Security 认证Authentication 验明正身——“你说你是张三密码拿来我瞅瞅”OAuth2 授权Authorization 发放通行证——“身份没问题给你发个令牌拿着它去访问别的服务吧”简单说就是Security负责“验人”OAuth2负责“发牌”。而我们今天要做的就是把原来那个单纯的Security认证服务改造成一个OAuth2授权服务器——让它既能验人又能发牌两全其美。第二幕动手改造三步搞定1.引入pom依赖!--OAuth2依赖--dependencygroupIdorg.springframework.security.oauth.boot/groupIdartifactIdspring-security-oauth2-autoconfigure/artifactIdversion2.3.9.RELEASE/version/dependency2.创建 OAuth2AuthorizationServerConfig,配置客户端信息以及授权类型Configuration//启用授权服务器功能EnableAuthorizationServerpublicclassOAuth2AuthorizationServerConfigextendsAuthorizationServerConfigurerAdapter{//用于验证用户的用户名和密码密码模式需要AutowiredprivateAuthenticationManagerauthenticationManager;//用于加密和验证客户端密钥AutowiredprivatePasswordEncoderpasswordEncoder;//定义令牌的存储方式BeanpublicTokenStoretokenStore(){// 使用 JWT 方式存储令牌// JWT 是一种自包含的令牌格式不需要在服务器端存储returnnewJwtTokenStore(accessTokenConverter());}//JWT 令牌转换器BeanpublicJwtAccessTokenConverteraccessTokenConverter(){JwtAccessTokenConverterconverternewJwtAccessTokenConverter();// 注意这里使用的是对称密钥默认// 生产环境建议使用非对称密钥RSAreturnconverter;}//这里定义了哪些应用可以访问 OAuth2 服务Overridepublicvoidconfigure(ClientDetailsServiceConfigurerclients)throwsException{// inMemory() - 将客户端信息存储在内存中// 生产环境应该使用 .jdbc() 存储在数据库中clients.inMemory()// 配置第一个客户端应用 客户端 ID类似用户名.withClient(client-app)// 客户端密钥类似密码需要加密.secret(passwordEncoder.encode(secret123))// 允许的授权类型四种模式授权码模式密码模式客户端凭证模式隐式模式刷新令牌.authorizedGrantTypes(authorization_code,password,client_credentials,implicit,refresh_token)// 允许的权限范围.scopes(read,write)// 回调地址.redirectUris(http://localhost:8080/callback)// 自动批准不需要用户手动确认授权.autoApprove(true)// 访问令牌有效期3600秒1小时.accessTokenValiditySeconds(3600)// 刷新令牌有效期7200秒2小时.refreshTokenValiditySeconds(7200).and()// 配置下一个客户端.withClient(web-app).secret(passwordEncoder.encode(web-secret)).authorizedGrantTypes(authorization_code,password,client_credentials,implicit,refresh_token).scopes(read,write).redirectUris(http://localhost:8080/web/callback).autoApprove(true).accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(7200);}//配置授权服务器端点Overridepublicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints)throwsException{endpoints// 设置认证管理器用于密码模式的用户认证.authenticationManager(authenticationManager)// 设置令牌存储方式JWT.tokenStore(tokenStore())// 设置令牌转换器JWT 转换.accessTokenConverter(accessTokenConverter());}//配置授权服务器的安全策略Overridepublicvoidconfigure(AuthorizationServerSecurityConfigurersecurity)throwsException{security// /oauth/token_key 端点允许所有人访问// 这个端点用于获取 JWT 签名的公钥如果使用非对称加密.tokenKeyAccess(permitAll())// /oauth/check_token 端点需要认证后才能访问// 这个端点用于验证令牌的有效性.checkTokenAccess(isAuthenticated())// 允许客户端通过表单方式提交认证信息// 这样客户端可以在 POST body 中传递 client_id 和 client_secret.allowFormAuthenticationForClients();}}3.改造一下 MyWebSecurityConfigAdapter放行 oauth2自带的接口并创建一个AuthenticationManager对象Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{http.csrf().disable().httpBasic();http.authorizeRequests().antMatchers(/oauth/**).permitAll().anyRequest().authenticated();}OverrideBeanpublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}第三幕实战测试看看效果先来测试一下密码模式本服务端口 8129用post请求 http://localhost:8129/oauth/tokenAuthorization 中 选择 Basic Auth 并 填入 用户名 client-app, 密码 secret123注意 这个用户名密码 是.withClient(client-app)// 客户端密钥类似密码需要加密.secret(passwordEncoder.encode(secret123))不是users表中 的 用户名密码然后在 body中添加参数注意选择 x-www-form-urlencodedgrant_type是.authorizedGrantTypes(authorization_code,password,client_credentials,implicit,refresh_token)哪个模式访问就写哪个这里的 username 和 password 才是 数据库中 users表的 用户名密码scope的值是// 允许的权限范围.scopes(read,write)现在我们来 send 一下返回的这一大串json就是 oauth2的令牌。客户端凭证模式这个跟密码模式的区别1无需提供 users 的用户名密码2grant_type 的值 变成 client_credentials这个模式通常用于服务与服务之间的内部调用比如定时任务、微服务互相拉取数据等场景——没有真人用户只有机器在互相对话。下集预告这一集我们把Security认证服务成功改造为OAuth2授权服务器跑通了密码模式和客户端凭证模式。下一集我们将真正创建一个前端应用完整跑通密码模式和授权码模式的登录流程。至于隐式模式没啥卵用可以忘掉它