
说明SpringAuthorizationServer遵循和,它建立在SpringSecurity之上。最小化项目创建项目要求JDK11以上使用Idea创建一个Maven的SpringBoot(笔者使......
SpringAuthorizationServer遵循和,它建立在SpringSecurity之上。
最小化项目创建项目要求JDK11以上
使用Idea创建一个Maven的SpringBoot(笔者使用的是)项目
pom需要引入AuthorizationServer的配置
/groupIdartifactIdspring-security-oauth2-authorization-server//version/depency复制代码
完整的文件如下:
?xmlversion="1.0"encoding="UTF-8"?projectxmlns=""xmlns:xsi=""xsi:schemaLocation=""//groupIdartifactIdspring-boot-starter-parent//versionrelativePath/!--lookupparentfromrepository--//groupIdartifactIdSpring_Authorization_Server_0_3_x//////propertiesdepencies!--必须引入--/groupIdartifactIdspring-security-oauth2-authorization-server//version/depency!--必须引入--/groupIdartifactIdspring-boot-starter-web/artifactId/depency!--可选引入--/groupIdartifactIdspring-boot-starter-actuator/artifactId/depency!--可选引入--/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/depency//groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project复制代码配置
使用@Bean和@Configuration创建配置,这是官方推荐的最小配置。
至此最小化项目完成,这就能够完成oauth2的授权。
测试授权码模式浏览器访问;client_id=messaging-clientscope=_uri=
输入用户名(user)密码(password)后
提交后,会自动跳转到redirect_uri地址,并且地址会紧跟着code。
返回的code是
axia5-kuIIzO1D1eu1V_02KawWIkRydiZrDEPAtLhNlYC7kLeUazD_bh5UXGQVJj7W2gxC1zpQJuQ2D9ZVrQyVfufxMYyv4fkjjMitiQ1gH-bGQ6KqGy5egeC15NfHBt复制代码
接下来需要使用这个code获取token(我用postman请求)。
获取token授权码获取token的请求地址是oauth2/token,post请求:
上线这个三个参数是必须的,并且要跟代码中设置完全一直,另外获取token要传递client_id和client_secret参数,默认不支持使用表单传递,要通过header传递。比如在postman中
其实上线的操作实际上就是在header中传递了一个header,key=Authorization,value是client_id:client_secret,然后使用base64加密的字符串,然后前面加上Basic(注意后面有空格)。对于我这个例子来说就是BasicbWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=
返回结果是:
{"access_token":"eyJraWQiOiIxNGMxO1NDMyMzg0OSwic2NvcGUiOlsibWVzc2FnZS5yZWFkIl0sImlzcyI6Imh0dHA6XC9cLzEyN_KRC2SnOH93nGYnoP2uWZwyiamke5PGWa72OHPxgwktgAxK0gHIjQ_sgh5tD4R2swb9bARIn2ZvUb3DtIXpLzEoCGRu4DqJoaUFnj71oAvX1MSruHeLqQaCwL2nJ-C-TNwj_mFHzcZFdaFZRQIIIkaG46Zgj1G0BCxpKtJy3FVIcbGJK-HYHHdh2XOMAIyCA5MrDn2VtZmJDwSbhSSEdU8jY8n41LPUd79koozIH_6onrx-y9ly3-evV3cAGBvsWA26h6PAR0Nxv47LXaUM5Hn_6OA20noCi53CC0qdahRJSs9eHpXsLd0rpjPDrk4nK9S7G0wTIlw","refresh_token":"2CvlhRXdg6EK0ZzS_3kI-AI-AeCXBFpvD1krSbu28sTundjXnwvZT4AuQ03rtUr5TD2VFUWyuAJ68fAmNIonUVSRaDKzdx-Z2Z61np_HlcBF2iUxLRyl4JW9jeBQ7CZG","scope":"","token_type":"Bearer","expires_in":299}复制代码刷新token结果是:
{"access_token":"eyJraWQiOiIxNGMxO1NDMyNDU1OCwic2NvcGUiOlsibWVzc2FnZS5yZWFkIl0sImlzcyI6Imh0dHA6XC9cLzEyN1hhjpl1d59RixOXkOAIK6PUI_-y_6MTmXL71YZ1lmrifhZ24bYkqXQKMAsbFvj3bXn6RyVnTwFsiy9IzZBRK_-PTPWQd9DbaYkmpryeZtGBqUFYAyBDrgCTYgw0SEoDI2qEX_W3Bgxiz9yTDH5Gszdbe0CzxvHP7LOGDi7-q-WziGhQCoMfFMK0P2WvzeAagseUEUpoSJTk8IMh-_8EgatrwilSYjkKKwgf_-hd9UXDi4bsW9MNA9iIDCYqKJ5dflTutoUJX8oxpnYTwP8iGNDA","refresh_token":"2CvlhRXdg6EK0ZzS_3kI-AI-AeCXBFpvD1krSbu28sTundjXnwvZT4AuQ03rtUr5TD2VFUWyuAJ68fAmNIonUVSRaDKzdx-Z2Z61np_HlcBF2iUxLRyl4JW9jeBQ7CZG","scope":"","token_type":"Bearer","expires_in":299}复制代码简化模式在中被移除
客户端模式获取token结果是:
{"access_token":"eyJraWQiOiIxNGMxOudCIsIm5iZiI6MTY1NDMyNDc5Nywic2NvcGUiOlsib3BlbmlkIiwibWVzc2FnZS5yZWFkIiwibWVzc2FnZS53cml0ZSJdLCJpc3MiOiJodHRwOlwvXC8xMjc_b9m3rd9-QqkQpuxbFBD_o4dk3wl7PKVlZuWNCVrcvEXMFREexU6wwKtzTWKTBWYtDOAvKJN81iJ34UqsXRQ_M3xvUlpVXMjFKY9c3hsP9te8FpfcMi4IZfnHS79CunTh7tgovEo53nu9UNQ2qKy_MR9a13cXpe_AepOP_68gaLO-SAdRI-H9L4e57Y3w7Lq-UWUxywtnAtEcnm_PTGaA-gIEvCiN0rx6pZFBOxv-58OhNfp79oTN33yBDN-E3dSWgioQDp-Sc7kIb8z-rzXa1ZQgx19xTGg","scope":"","token_type":"Bearer","expires_in":299}复制代码客户端模式没有刷新token模式。
密码模式在中被移除
配置默认配置之前已经通过最小配置,完成了一个SpringAuthorizationServer项目,本章学习下关于配置的内容。
SpringAuthorizationServer还提供了一种实现最小配置的默认配置形式。就是通过OAuth2AuthorizationServerConfiguration这个类。
看下这个类的源码:
/**Copyright2020-2021theoriginalauthororauthors.**LicensedundertheApacheLicense,(the"License");*youmaynotusethisfileexceptincompliancewiththeLicense.*YoumayobtainacopyoftheLicenseat****Unlessrequiredbyapplicablelaworagreedtoinwriting,software*distributedundertheLicenseisdistributedonan"ASIS"BASIS,*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.*SeetheLicenseforthespecificlanguagegoverningpermissionsand*limitationsundertheLicense.*/;;;;;;;;;;;;;;;;;;;;;/***{@linkConfiguration}**@authorJoeGrandja*@*@seeOAuth2AuthorizationServerConfigurer*/@Configuration(proxyBeanMethods=false)publicclassOAuth2AuthorizationServerConfiguration{@Bean@Order(_PRECEDENCE)publicSecurityFilterChainauthorizationServerSecurityFilterChain(HttpSecurityhttp)throwsException{applyDefaultSecurity(http);();}//@formatter:offpublicstaticvoidapplyDefaultSecurity(HttpSecurityhttp)throwsException{OAuth2AuthorizationServerConfigurerHttpSecurityauthorizationServerConfigurer=newOAuth2AuthorizationServerConfigurer();RequestMatcherpointsMatcher=();(pointsMatcher).authorizeRequests(().authenticated()).csrf((pointsMatcher)).apply(authorizationServerConfigurer);}//@formatter:onpublicstaticJwtDecoderjwtDecoder(JWKSourceSecurityContextjwkSource){SetJWSAlgorithmjwsAlgs=newHashSet();();();(_SHA);ConfigurableJWTProcessorSecurityContextjwtProcessor=newDefaultJWTProcessor();JWSKeySelectorSecurityContextjwsKeySelector=newJWSVerificationKeySelector(jwsAlgs,jwkSource);(jwsKeySelector);//OverridethedefaultNimbus((claims,context)-{});returnnewNimbusJwtDecoder(jwtProcessor);}@BeanRegisterMissingBeanPostProcessorregisterMissingBeanPostProcessor(){RegisterMissingBeanPostProcessorpostProcessor=newRegisterMissingBeanPostProcessor();(,()-().build());returnpostProcessor;}}复制代码这里注入一个叫做authorizationServerSecurityFilterChain的bean,这跟我之前最小化项目时实现的基本是相同的。
有了这个bean,就会支持如下协议端点:
OAuth2Authorizationpoint
OAuth2Tokenpoint
OAuth2TokenIntrospectionpoint
OAuth2TokenRevocationpoint
OAuth2AuthorizationServerMetadatapoint
JWKSetpoint
接来我我尝试使用OAuth2AuthorizationServerConfiguration这个类来实现一个AuthorizationServer。
SpringSecurity使用SecurityConfig类,创建一个新的AuthorizationServer配置类AuthorizationServerConfig。
SecurityConfig类配置如下:
代码如下:
;;;;;;;;;;;;;;;;;;;;;;@Configuration@Import()publicclassAuthorizationServerConfig{/***oauth2用于第三方认证,RegisteredClientRepository主要用于管理第三方(每个第三方就是一个客户端)**@return*/@BeanpublicRegisteredClientRepositoryregisteredClientRepository(){RegisteredClientregisteredClient=(().toString()).clientId("messaging-client").clientSecret("{noop}secret").clientAuthenticationMethod(_SECRET_BASIC).authorizationGrantType(_CODE).authorizationGrantType(_TOKEN).authorizationGrantType(_CREDENTIALS).redirectUri("").redirectUri("").scope().scope("").scope("").clientSettings(().requireAuthorizationConsent(true).build()).build();returnnewInMemoryRegisteredClientRepository(registeredClient);}/***用于给access_token签名使用。**@return*/@BeanpublicJWKSourceSecurityContextjwkSource(){KeyPairkeyPair=generateRsaKey();RSAPublicKeypublicKey=(RSAPublicKey)();RSAPrivateKeyprivateKey=(RSAPrivateKey)();RSAKeyrsaKey=(publicKey).privateKey(privateKey).keyID(().toString()).build();JWKSetjwkSet=newJWKSet(rsaKey);returnnewImmutableJWKSet(jwkSet);}/***生成秘钥对,为jwkSource提供服务。**@return*/privatestaticKeyPairgenerateRsaKey(){KeyPairkeyPair;try{KeyPairGeneratorkeyPairGenerator=("RSA");(2048);keyPair=();}catch(Exceptionex){thrownewIllegalStateException(ex);}returnkeyPair;}}复制代码至此可以实现了AuthorizationServer。
测试客户端调用。
授权码模式测试
授权码模式也没有问题。
存储配置SpringAuthorizationServer默认是支持内存和JDBC两种存储模式的,内存模式只适合开发和简单的测试。接下来我们来实现JDBC存储方式。
修改步骤如下:
引入JDBC相关依赖。
创建数据库并初始化表,以及在文件中配置数据库连接。
修改SpringSecurity和SpringauthorizationServer的配置。
初始化表数据
测试服务
接下来我依次实现。
引入JDBC相关依赖
/groupIdartifactIdspring-boot-starter-jdbc/artifactId//groupIdartifactIdpostgresql/artifactIdscoperuntime/scope/depency复制代码
创建数据库并初始化表,以及在文件中配置数据库连接。
createtableoauth2_authorization(idvarchar(100)notnullprimarykey,registered_client_idvarchar(100)notnull,principal_namevarchar(200)notnull,authorization_grant_typevarchar(100)notnull,attributesblobnull,statevarchar(500)null,authorization_code_valueblobnull,authorization_code_issued_attimestampnull,authorization_code_expires_attimestampnull,authorization_code_metadatablobnull,access_token_valueblobnull,access_token_issued_attimestampnull,access_token_expires_attimestampnull,access_token_metadatablobnull,access_token_typevarchar(100)null,access_token_scopesvarchar(1000)null,oidc_id_token_valueblobnull,oidc_id_token_issued_attimestampnull,oidc_id_token_expires_attimestampnull,oidc_id_token_metadatablobnull,refresh_token_valueblobnull,refresh_token_issued_attimestampnull,refresh_token_expires_attimestampnull,refresh_token_metadatablobnull);createtableoauth2_authorization_consent(registered_client_idvarchar(100)notnull,principal_namevarchar(200)notnull,authoritiesvarchar(1000)notnull,primarykey(registered_client_id,principal_name));createtableoauth2_registered_client(idvarchar(100)notnullprimarykey,client_idvarchar(100)notnull,client_id_issued_attimestampdefaultCURRENT_TIMESTAMPnotnull,client_secretvarchar(200)null,client_secret_expires_attimestampnull,client_namevarchar(200)notnull,client_authentication_methodsvarchar(1000)notnull,authorization_grant_typesvarchar(1000)notnull,redirect_urisvarchar(1000)null,scopesvarchar(1000)notnull,client_settingsvarchar(2000)notnull,token_settingsvarchar(2000)notnull);createtableusers(usernamevarchar(50)notnullprimarykey,passwordvarchar(500)notnull,enabledtinyint(1)notnull);createtableauthorities(usernamevarchar(50)notnull,authorityvarchar(50)notnull,constraintix_auth_usernameunique(username,authority),constraintfk_authorities_usersforeignkey(username)referencesusers(username));复制代码
初始化表,建表语句在哪里?
SpringSecurity的建表语句在
org/springframework/security/core/userdetails/jdbc/复制代码
SpringauthorizationServer的建表文件在:
org/springframework/security/oauth2/server/authorization//springframework/security/oauth2/server/authorization//springframework/security/oauth2/server/authorization/client/复制代码
都在jar包中,并且sql可能会有问题,请大家根据自己使用的数据库进行修改。
配置文件中配置数据库连接信息
server:port:8080spring:main:allow-bean-definition-overriding:truedatasource:url:jdbc:mysql://localhost:3306/spring-authorization-serverdriver-class-name::rootpassword:qwe!@#123复制代码
请根据自己的情况进行修改。
修改SpringSecurity和SpringauthorizationServer的配置。
修改SecurityConfig中的UserDetailsServicebean。
@AutowiredprivateDataSourcedataSource;@BeanpublicUserDetailsServiceuserDetailsService(){returnnewJdbcUserDetailsManager(dataSource);}复制代码SpringAuthorizationServer有三张表,对应的bean也要修改三处
@AutowiredJdbcTemplatejdbcTemplate;@BeanpublicRegisteredClientRepositoryregisteredClientRepository(){returnnewJdbcRegisteredClientRepository(jdbcTemplate);}@BeanpublicOAuth2AuthorizationServiceauthorizationService(){returnnewJdbcOAuth2AuthorizationService(jdbcTemplate,registeredClientRepository());}@BeanpublicOAuth2AuthorizationConsentServiceauthorizationConsentService(){returnnewJdbcOAuth2AuthorizationConsentService(jdbcTemplate,registeredClientRepository());}复制代码上述三个类对应SpringAuthorizationServer的三个表。
初始化表数据
需要初始化三张表数据,分别是users,authorities,oauth2_registered_client
users,authorities需要通过UserDetailsManager类来实现,我暂时使用junitTest来实现。
;;;;;;;;;;@SpringBootTestclassApplicationTests{/***初始化客户端信息*/@AutowiredprivateUserDetailsManageruserDetailsManager;/***创建用户信息*/@TestvoidtestSaveUser(){UserDetailsuserDetails=()..passwordEncoder(s-"{bcrypt}"+newBCryptPasswordEncoder().encode(s)).username("user").password("password").roles("ADMIN").build();(userDetails);}}复制代码执行完毕后两个表的记录如下:
users:
username
password
enabled
user
2a2a2a10$
1
authories:
username
authority
user
ROLE_ADMIN
创建client信息
/***创建clientId信息*/@AutowiredprivateRegisteredClientRepositoryregisteredClientRepository;@Test@TestvoidtestSaveClient(){RegisteredClientregisteredClient=(().toString()).clientId("messaging-client").clientSecret("{bcrypt}"+newBCryptPasswordEncoder().encode("secret")).clientAuthenticationMethod(_SECRET_BASIC).authorizationGrantType(_CODE).authorizationGrantType(_TOKEN).authorizationGrantType(_CREDENTIALS).redirectUri("").redirectUri("").scope().scope("").scope("").clientSettings(().requireAuthorizationConsent(true).build()).build();(registeredClient);}复制代码创建完成后,oauth2_registered_client表中的记录如下:
id
client_id
client_id_issued_at
client_secret
client_secret_expires_at
client_name
client_authentication_methods
authorization_grant_types
redirect_uris
scopes
client_settings
token_settings
f0ff36c2-1245-41a6-8c92-5ac5c049b268
messaging-client
2022-07-0220:35:26
{bcrypt}2a2a2a10$/O9UXXL721nH2s/2oOoH2UwOfc32.
NULL
f0ff36c2-1245-41a6-8c92-5ac5c049b268
client_secret_basic
refresh_token,client_credentials,authorization_code
openid,,
{"@class":"$UnmodifiableMap","":false,"":true}
{"@class":"$UnmodifiableMap","":true,"":["","RS256"],"":["",300.000000000],"":{"@class":"","value":"self-contained"},"":["",3600.000000000]}
测试服务
授权码模式
访问:;client_id=messaging-clientscope=_uri=
输入用户名密码(user,password)后,勾选scope,确认后,通过地址栏能或得code。
获取到的code是
ZPO_JhUNM69j46JqZIGTTE_fvyzdZ30irinvQEW1DwFBQmWKhrwX-3GhR0a1l6uRoo4au9P1xl8Y6ig8SwDtXyTMLeSyHZC5PN8qwYwDkucQVqQLD7zNZLsdOIOwtLT5复制代码
获取token
结果是:
{"access_token":"eyJraWQiOiJmZGZkN21Njc2NTczNiwic2NvcGUiOlsibWVzc2FnZS5yZWFkIl0sImlzcyI6Imh0dHA6XC9cLzEyN_lzu4EypPPniy9_34ZquBgAMBGaRGZyLwuJZ7dWeKLv9WZLtgtZQiGM4Ru8Z3_Ub8JYAdW8Sik0ZigSHjMIV1HlI50RzEN1ZNQ2OrmRf-XPAhfAnvC2y4VLNIIgtG-hMq1v6xjr70AZMQanRseapv8sM72rNaD71OWP6FxJb5mN8ZVv3DbNjMRUJ4YF5OTINx6igUB0nONEE1KJTmEYIFz4de7O3RuNhtuyaKFq1BId5pqE17uwxIp7X0cX5MD680l2wsoILqW_WlULHBVc2SHaI--Ku65tePP-cPPw","refresh_token":"uWbL6c1QgwR-C5yORCY6qxR5-hN4qRZ91z6fsBtX0_6HkAeKaThattFt8tLwz91OsW7v5W2OwoDLnFwhjgfUCSKWxfyW2_OQMizlC0ytsgFRhYnwcy7j-2YB4EN0h9Es","scope":"","token_type":"Bearer","expires_in":299}复制代码刷新token
结果是:
{"access_token":"eyJraWQiOiJmZGZkN21Njc2NTgwOSwic2NvcGUiOlsibWVzc2FnZS5yZWFkIl0sImlzcyI6Imh0dHA6XC9cLzEyN_AyF8ej843rhWGFh8ne2AoEAK98-kcsYh2B3JGzFnL5YBsDCSWhIDA6j-XLsF2bCcb7KDkREfeAL8tkkSE1wYm8nevcDufPMgyrZQEwHFWYoBAqCHUB2zPCx8PmInKa0aGkZIN6KJbdSWfp_-tFchi8sn6ZwPJkr5gU9NvoddbIAKm9A-6AT_EGXnlupo1ME26PptrLmrISOvDlbpOToCYMvSm9r22AzU2AITaM-9rujql_9H-Lj7ML8gMak2VJCPfSGpPczlvBG6fnP3xcwW6xXBd6wpe-tI7Cu6Bz36Hh2KIJlGs07_MvAxoCPixJIg","refresh_token":"uWbL6c1QgwR-C5yORCY6qxR5-hN4qRZ91z6fsBtX0_6HkAeKaThattFt8tLwz91OsW7v5W2OwoDLnFwhjgfUCSKWxfyW2_OQMizlC0ytsgFRhYnwcy7j-2YB4EN0h9Es","scope":"","token_type":"Bearer","expires_in":299}复制代码客户端模式:
获取token
结果是:
{"access_token":"eyJraWQiOiJmZGZkN2udCIsIm5iZiI6MTY1Njc2NTg4Miwic2NvcGUiOlsib3BlbmlkIiwibWVzc2FnZS5yZWFkIiwibWVzc2FnZS53cml0ZSJdLCJpc3MiOiJodHRwOlwvXC8xMjc_IZM_4YbZL_1Rarpi5uBb6CbqUzqbUyAy-NXhFRqJfUkcVvXEQ8MWcvY6bPILg_Aqi4T5ZlFij0OACmqE3QmEenEkAJ8cxBA_fl9-k_Wcv8faepP5dlX8apPTX5i_6DW5p8IxtM1-tonhWNEEHjVVVpaktTd0yLYlhe_bbcVHpNAHpYXSO9sl18EamAJC5j9-rgN02w3XMPMd7oLxfR6IN74jOynSK4dZUmT6NnKqq9_V0DWGJWXHCjddiVN85VS5mojoz_74DaFT480fuy9XmhoYhv1xFqPxpqSUQrlCwKzAktbCvka8b9vPXQ","scope":"","token_type":"Bearer","expires_in":299}复制代码自定义jwt字段将上面的jwt解码后结果如下:
接下来我们增加一个自定义header和claim.
需要使用OAuth2TokenCustomizer来实现。
@BeanpublicJwtEncoderjwtEncoder(){returnnewNimbusJwtEncoder(jwkSource());}@BeanpublicOAuth2TokenGenerator?tokenGenerator(){JwtGeneratorjwtGenerator=newJwtGenerator(jwtEncoder());(jwtCustomizer());OAuth2AccessTokenGeneratoraccessTokenGenerator=newOAuth2AccessTokenGenerator();OAuth2RefreshTokenGeneratorrefreshTokenGenerator=newOAuth2RefreshTokenGenerator();returnnewDelegatingOAuth2TokenGenerator(jwtGenerator,accessTokenGenerator,refreshTokenGenerator);}@BeanpublicOAuth2TokenCustomizerJwtEncodingContextjwtCustomizer(){returncontext-{=();=();if(().equals(_TOKEN)){//Customizeheaders/claimsforaccess_("customerHeader","这是一个自定义header");("customerClaim","这是一个自定义Claim");}elseif(().getValue().equals(_TOKEN)){//Customizeheaders/claimsforid_token}};}复制代码重启应用,我通过客户端模式获取token,并解码查看。
协议SpringAuthorizationServer支持协议,同时也支持协议,该协议是OAuth2协议的上层协议,这里我就不解释了,可自行百度。
默认是不支持该协议的,需要我们进行配置。
用户端点需要修改authorizationServerSecurityFilterChain为如下内容:
(oidc-{((oidcUserInfoAuthenticationContext-{OAuth2AccessTokenaccessToken=();MapString,Objectclaims=newHashMap();("url","");("accessToken",accessToken);("sub",().getPrincipalName());returnnewOidcUserInfo(claims);}));});(OAuth2ResourceServerConfigurer::jwt);@BeanpublicJwtDecoderjwtDecoder(JWKSourceSecurityContextjwkSource){(jwkSource);}复制代码请注意:我的client(messaging-client)设置的时候scope设置了openid的支持。
测试:
授权码模式获取token:
;client_id=messaging-clientscope=openidredirect_uri=
请再次注意,这里的scope必须包含openid。
输入用户名密码确认后,获得的code如下:
nngt651MwKjuKPK0NJfxOU6KHE6okJ8RK3P7fdyJuc2o_GXdaDTrQGnBYjabcH9Bj9sZR6mxlZuojhldB349NZgKBfl8P67BWuX5jmCzXBc-a48pv-rPAyP7kBVvc031复制代码
获取token,得到的token是:
{"access_token":"eyJjdXN0b21lckhlYWRlciI6Iui_meaYr-S4gOS4quiHquWumuS5iWhlYWRlciIsImFsZyI6IlJTMjU2yQ2xhaW0iOiLov5nmmK_kuIDkuKroh6rlrprkuYlDbGFpbSIsIm5iZiI6MTY1Njc2OTMzNiwic2NvcGUiOlsib3BlbmlkIl0sImlzcyI6Imh0dHA6XC9cLzEyNFxd-1CIVE7hyojwxOT4d7QASUr33LdlWY8rlJ4vDm9VzQwQstB1K1bCgWg5ZcKpWdDXBrcA2ZL14tNvpDH9qsTfFpuIM1pGc-YWFL5k3CuPU0Us_U-P6gQqxpdJsBebctCXyPncmXA7zVp60kGPtenR0E9mjBx7DMZ30L00Hm9bZgHiy5G4QI87KRuJh9tR187ZK08IW3-0UEU-pzDhWE1YJaC0k4lQSC1ZplJq2q0Cmi2E_p2ZtxK4uduNol2-TZtiNs33O83XrAN1X5hke-ew","refresh_token":"RFxOTgEWcN__IbJC2D0I1qS0lq7rEDr7OTQApwZRq6edAQubjeGXTRn0_2VKnP2lYdSLiGKn4IzrrcPpJ7mFFEgppTQJpnGSX2kE_9tJ9D8ImFE8mOEc5HLkW0G6TXBR","scope":"openid","id_token":"eyJraWQiOiIwMzQ5Mlc3NhZ2luZy1jbGllbnQiLCJpc3MiOiJodHRwOlwvXC8xMjcSTwI47PFeKvUevmeeTCNRncQKWe_FBbgB8ZilI4Q944zLIUUUQmZHlANNfQ8EhBdbnJ2b3iblvhxSOGNCV_nSc2Rg0oikjpxbalWQjfuJHDsqKFny4ReU-ziZLc7Q5PVu3xuNfQN_iZOZq2c7pu6e5sP0p3YoD_YrjimAk0Ich0wrqiR_a9N5lT-EDh0iGWUc6US-FljEWxm-W1sUwS3E5xxSZxY2AJcmSXBIckwxVeWzG0VP9JoSEPrrs6tErzUwEJzkiw-zxYDPJvMb9sO8fw","token_type":"Bearer","expires_in":299}复制代码通过token,获取OIDC的用户端点:
这里的sub就是用户的标志,当然也可以增加很多自定义信息。
修改如下:
@Bean@Order(_PRECEDENCE)publicSecurityFilterChainauthorizationServerSecurityFilterChain(HttpSecurityhttp)throwsException{OAuth2AuthorizationServerConfigurerHttpSecurityauthorizationServerConfigurer=newOAuth2AuthorizationServerConfigurer();RequestMatcherpointsMatcher=();(pointsMatcher).authorizeRequests(().authenticated()).csrf((pointsMatcher)).apply(authorizationServerConfigurer);http//Redirecttotheloginpagewhennotauthenticatedfromthe//((exceptions)-(newLoginUrlAuthenticationEntryPoint("/login")));//也可以使用如下代码,跳转到loginpage//(());(oidc-{((oidcUserInfoAuthenticationContext-{OAuth2AccessTokenaccessToken=();MapString,Objectclaims=newHashMap();("url","");("accessToken",accessToken);("sub",().getPrincipalName());returnnewOidcUserInfo(claims);}));});(OAuth2ResourceServerConfigurer::jwt);();}复制代码重新获取用户信息,得到如下内容:
{"accessToken":{"tokenValue":"eyJjdXN0b21lckhlYWRlciI6Iui_meaYr-S4gOS4quiHquWumuS5iWhlYWRlciIsImFsZyI6IlJTMjU2yQ2xhaW0iOiLov5nmmK_kuIDkuKroh6rlrprkuYlDbGFpbSIsIm5iZiI6MTY1Njc3MDkxMSwic2NvcGUiOlsib3BlbmlkIl0sImlzcyI6Imh0dHA6XC9cLzEyNjpEakmd_byUlLkNC9sfGhae7t5U9fGgu6YzWhq3EKn-4g8TCJLMg6G8kmzCuqgLx6t_AaDDwhUQ7lsrVu99lahvE57mP80RmRGTBCnMbxfKbzvdj0nsMW0awYANd0R9m__gYL-O5WWAc7-qrcylPMzIKTOqT-cX2-pKzlAuhpcxsupQSNdnCEoH_VeoICMqcJnsz2l8mQjmHOnQ9YAddCvnLGeXcqyW24KhnUcJ0LwZLYrrvGdZ323lQKZSytTXfc4d9O1OzGkwR9OYmKif8Xbg","issuedAt":1656770912.000000000,"expiresAt":1656771212.000000000,"tokenType":{"value":"Bearer"},"scopes":["openid"]},"url":"""sub":"user"}复制代码实际开发中,我们可以自定义,昵称、性别,头像等非敏感信息。
查看OpenID的配置结果是:
{"issuer":"http://localhost:8080","authorization_point":"http://localhost:8080/oauth2/authorize","token_point":"http://localhost:8080/oauth2/token","token_point_auth_methods_supported":["client_secret_basic","client_secret_post","client_secret_jwt","private_key_jwt"],"jwks_uri":"http://localhost:8080/oauth2/jwks","userinfo_point":"http://localhost:8080/userinfo","response_types_supported":["code"],"grant_types_supported":["authorization_code","client_credentials","refresh_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"],"scopes_supported":["openid"]}复制代码客户端注册端点客户端注册端点默认禁用,因为许多部署不需要动态客户端注册。
增加如下配置:
@Bean@Order(_PRECEDENCE)publicSecurityFilterChainauthorizationServerSecurityFilterChain(HttpSecurityhttp)throwsException{OAuth2AuthorizationServerConfigurerHttpSecurityauthorizationServerConfigurer=newOAuth2AuthorizationServerConfigurer();RequestMatcherpointsMatcher=();(pointsMatcher).authorizeRequests(().authenticated()).csrf((pointsMatcher)).apply(authorizationServerConfigurer);http//Redirecttotheloginpagewhennotauthenticatedfromthe//((exceptions)-(newLoginUrlAuthenticationEntryPoint("/login")));//也可以使用如下代码,跳转到loginpage//(());(oidc-{//用户信息((oidcUserInfoAuthenticationContext-{OAuth2AccessTokenaccessToken=();MapString,Objectclaims=newHashMap();("url","");("accessToken",accessToken);("sub",().getPrincipalName());returnnewOidcUserInfo(claims);}));//客户端注册(());});(OAuth2ResourceServerConfigurer::jwt);();}复制代码请注意:
测试:
请求:;client_id=messaging-clientscope=_uri=
输入用户名密码后:
勾选scope,并提交,从地址栏中获取到code。
qdd5jgQxyfAlZELZr8kclamAaqkXlWxoEPa5h_7E0BbNLDkgfjDLnpo5SmPrFbZxZJVwO3KCMpmQD5D_y-2e_in8UD50ZpDPNs5GXjvOs_vU-tjhf0V-A7C9H1Phf9gw复制代码
获取accessToken
json结果是:
{"access_token":"eyJjdXN0b21lckhlYWRlciI6Iui_meaYr-S4gOS4quiHquWumuS5iWhlYWRlciIsImFsZyI6IlJTMjU2yQ2xhaW0iOiLov5nmmK_kuIDkuKroh6rlrprkuYlDbGFpbSIsIm5iZiI6MTY1Njg1NjAyMCwic2NvcGUiOlsiY2xpZW50LmNyZWF0ZSJdLCJpc3MiOiJodHRwOlwvXC8xMjc_udeDSZEdozy9iNCoEENcLWRsBh_RPRiQ6gx-IVXZouTnQkvl_nJChSDRv6a75HqDnxW3Q_iFQlxJx9wbXUIJ1k4mt2q0VqfPS5tTKoblhuEdAKyL90RLAEP1BSzxFFEYeSKIl-nEwsUWsZY9mqnzw33Z1dRVgZLrhIdhpwg41sSFKqw6B5yRzOHrc_0_nAW10TJK9ONbxrJvTc2ZHI8yLBjRoqEdFPgcOMkBHAH8baGsoHNLGEbVK4U8fb_hvZ1F9Ara3Aw3_yga4kJciGi_yt6y-A","refresh_token":"Hux9d04U-mi1GIFhy3t244xpS9wvrDaPSYXoR0gRP6vlQuKqAWlEER8RbdP7EAGOuFGoAyZ-nKAoxBL5JZxuwIyoGECrgHTEnof5eDaMVdrbNzwr8B8xxSZ0f-JicBys","scope":"","token_type":"Bearer","expires_in":299}复制代码通过获取的accessToken,POST请求/connect/register接口
返回结果:
{"client_id":"Gw-kfSnh0R948WSJnAdIQCbXtcfifFhDygB7vPOWieI","client_id_issued_at":1656856140,"client_name":"MyExample","client_secret":"lmngmSlQNBJdCpBO4Ha2gubD0jtK_3Px2khf-u_tpyFZAT6imLV5F_bcsyZCZXPd","redirect_uris":["",""],"grant_types":["authorization_code"],"response_types":["code"],"token_point_auth_method":"client_secret_basic","id_token_signed_response_alg":"RS256","registration_client_uri":"","registration_access_token":"eyJjdXN0b21lckhlYWRlciI6Iui_meaYr-S4gOS4quiHquWumuS5iWhlYWRlciIsImFsZyI6IlJTMjU2XaWVJIiwiYXVkIjoiR3cta2ZTbmgwUjk0OFdTSm5BZElRQ2JYdGNmaWZGaER5Z0I3dlBPV2llSSIsImN1c3RvbWVyQ2xhaW0iOiLov5nmmK_kuIDkuKroh6rlrprkuYlDbGFpbSIsIm5iZiI6MTY1Njg1NjE0MCwic2NvcGUiOlsiY2xpZW50LnJlYWQiXSwiaXNzIjoiaHR0cDpcL1wvMTI3Ytv1rmrC8lbljycMXGcGRgBUSL1Zi5AFSoGCflYnVLvgHEQE70WLlcTFf4SW3JTQTBd2iTpTxAnNOQLG8UYgfDj4KQRAqkmdUUxNc-mPdpUNJQcDciNUgvuW5YhED3aPEVEp4tNfF47umyMUJ5kSGdFNOc3JDVI_nFE3TajxP1WYzvbF5SY8rq7TEtQPz1SB-YwSKZwusABjRQrmQAn0-oI-c-MvxjbyzMQPG6XXDArVv9rSfuouShU6VZYnPhL4t_D11RLPvL62AiLNya1VzIQ","client_secret_expires_at":0}复制代码查看数据库表(oauth2_registered_client),可以看到多了一条记录
id
client_id
client_id_issued_at
client_secret
client_secret_expires_at
client_name
client_authentication_methods
authorization_grant_types
redirect_uris
scopes
client_settings
token_settings
f60a7102-08f6-4217-99c8-6d73a5dba9ef
Gw-kfSnh0R948WSJnAdIQCbXtcfifFhDygB7vPOWieI
2022-07-0321:49:01
lmngmSlQNBJdCpBO4Ha2gubD0jtK_3Px2khf-u_tpyFZAT6imLV5F_bcsyZCZXPd
NULL
MyExample
client_secret_basic
authorization_code
/callback,ht…
{"@class":"$UnmodifiableMap","":true,"":true}
{"@class":"$UnmodifiableMap","":true,"":["","RS256"],"":["",300.000000000],"":{"@class":"","value":"self-contained"},"":["",3600.000000000]}
说明客户端已经注册成功。