当前位置: 首页 > news >正文

什么叫网站规划网站建设运营服务商

什么叫网站规划,网站建设运营服务商,租用了空间 怎样上传网站程序,辽宁省网站备案之所以想写这一系列#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器#xff0c;但当时基于spring-boot 2.3.x#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0#xff0c;结果一看Spring Security也升级…之所以想写这一系列是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器但当时基于spring-boot 2.3.x其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动里面甚至将授权服务器模块都移除了导致在配置同样功能时花费了些时间研究新版本的底层原理这里将一些学习经验分享给大家。 注意由于框架不同版本改造会有些使用的不同因此本次系列中使用基本框架是 spring-boo-3.3.0默认引入的Spring Security是6.3.0JDK版本使用的是19本系列OAuth2的代码采用Spring Security6.3.0框架所有代码都在oauth2-study项目上https://github.com/forever1986/oauth2-study.git 目录 1 客户端认证原理2 Spring Authrization Server客户端表说明3 基于数据库客户端3.1 自带的Jdbc实现类3.2 使用自带的Jdbc实现 4 基于自定义数据库客户端 前面我们自定义了授权页面但是截止到目前为止我们的客户端应用注册都是放在yaml文件或者在代码中加入其实就是基于内存存储中这样会导致每次增加客户端都要重启。在实际项目中一般会放在数据库或者Redis缓存中本章就将实现基于数据库的客户端应用注册。在了解如何自定义基于数据库的客户端之前我们先来了解一下客户端认证的原理 1 客户端认证原理 我们知道Spring Authrization Server虽然从Spring Security分离出来但是底层还是基于Spring Security的如果读过Spring Security 6系列之二的朋友应该很快就能掌握这一部分因为实现的方式几乎一样。 1看源码就是直接看过滤器我们先看看OAuth2AuthorizationEndpointFilter其doFilterInternal方法中就做了认证 2从上图可以知道基于AuthenticationManager而AuthenticationManager只是一个接口实际的实现类ProviderManager。但是其实ProviderManager只是一个代理。ProviderManager里面有一个AuthenticationProvider数组通过这个数据实现不同认证的。这部分都是Spring Security的内容 3客户端信息是通过OAuth2AuthorizationCodeRequestAuthenticationProvider实现类的 4到此我们就知道获取客户端信息就是使用RegisteredClientRepository我们再看看RegisteredClientRepository返回的是客户端信息放在一个RegisteredClient类另外RegisteredClientRepository有两个实现类 InMemoryRegisteredClientRepository基于内存我们在yaml文件中配置都是基于内存这个系列一中Spring Boot自动化配置可以找到注入原理JdbcRegisteredClientRepository基于数据库可以看到该类是基于传统的Jdbc方式实现 从原理分析我们知道要么我们直接使用JdbcRegisteredClientRepository要么就自定义一个RegisteredClientRepository。下面我们先了解相关的数据库表。 2 Spring Authrization Server客户端表说明 既然要保存到数据库那么就需要做数据库表Spring Authrization Server已经为我们准备好了SQL但不是一张表而是3张表。如下图Spring Authrization Server有三张跟OAuth2流程有关的表分别是oauth2_registered_client客户端表、oauth2_authorization授权表、oauth2_authorization_consent 授权确认表下面说一下3张表作用和流程 1首先是你需要将授权服务器中原先在yaml文件中配置的客户端信息存入oauth2_registered_client客户端表2当你进入授权页面时授权服务器会往oauth2_authorization授权表中插入一条授权信息3当你确认授权之后授权服务器会更新oauth2_authorization授权表的信息同时往oauth2_authorization_consent 授权确认表插入一条关联oauth2_registered_client表和oauth2_authorization表的记录这样下次就不用再次授权 客户端信息表保存客户端信息的可以参考一下注解大概知道其字段含义 CREATE TABLE oauth2_registered_client (-- 唯一标识idid varchar(100) NOT NULL,-- 注册客户端idclient_id varchar(100) NOT NULL,-- 注册客户端签发时间默认是当前时间client_id_issued_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,-- 注册客户端密钥client_secret varchar(200) DEFAULT NULL,-- 注册客户端过期时间client_secret_expires_at timestamp DEFAULT NULL,-- 注册客户端名称client_name varchar(200) NOT NULL,-- 注册客户端验证方法client_authentication_methods varchar(1000) NOT NULL,-- 注册客户端授权模式授权码模式、客户端模式等authorization_grant_types varchar(1000) NOT NULL,-- 注册客户端回调地址redirect_uris varchar(1000) DEFAULT NULL,-- 注册客户端首页post_logout_redirect_uris varchar(1000) DEFAULT NULL,-- 注册客户端授权范围scopes varchar(1000) NOT NULL,-- 注册客户端配置client_settings varchar(2000) NOT NULL,-- token配置token_settings varchar(2000) NOT NULL,PRIMARY KEY (id) );授权信息表授权信息在跳转到授权页面时会插入一条信息。 /* IMPORTANT:If using PostgreSQL, update ALL columns defined with blob to text,as PostgreSQL does not support the blob data type. */ CREATE TABLE oauth2_authorization (id varchar(100) NOT NULL,registered_client_id varchar(100) NOT NULL,principal_name varchar(200) NOT NULL,authorization_grant_type varchar(100) NOT NULL,authorized_scopes varchar(1000) DEFAULT NULL,attributes blob DEFAULT NULL,state varchar(500) DEFAULT NULL,authorization_code_value blob DEFAULT NULL,authorization_code_issued_at timestamp DEFAULT NULL,authorization_code_expires_at timestamp DEFAULT NULL,authorization_code_metadata blob DEFAULT NULL,access_token_value blob DEFAULT NULL,access_token_issued_at timestamp DEFAULT NULL,access_token_expires_at timestamp DEFAULT NULL,access_token_metadata blob DEFAULT NULL,access_token_type varchar(100) DEFAULT NULL,access_token_scopes varchar(1000) DEFAULT NULL,oidc_id_token_value blob DEFAULT NULL,oidc_id_token_issued_at timestamp DEFAULT NULL,oidc_id_token_expires_at timestamp DEFAULT NULL,oidc_id_token_metadata blob DEFAULT NULL,refresh_token_value blob DEFAULT NULL,refresh_token_issued_at timestamp DEFAULT NULL,refresh_token_expires_at timestamp DEFAULT NULL,refresh_token_metadata blob DEFAULT NULL,user_code_value blob DEFAULT NULL,user_code_issued_at timestamp DEFAULT NULL,user_code_expires_at timestamp DEFAULT NULL,user_code_metadata blob DEFAULT NULL,device_code_value blob DEFAULT NULL,device_code_issued_at timestamp DEFAULT NULL,device_code_expires_at timestamp DEFAULT NULL,device_code_metadata blob DEFAULT NULL,PRIMARY KEY (id) ); 确认授权表授权确认后就会将客户端表的记录与授权信息表的记录关联在一起并记录授权情况 CREATE TABLE oauth2_authorization_consent (registered_client_id varchar(100) NOT NULL,principal_name varchar(200) NOT NULL,authorities varchar(1000) NOT NULL,PRIMARY KEY (registered_client_id, principal_name) ); 这3个信息都有内存和数据库实现方式默认都是内存方式。 3 基于数据库客户端 我们先展现以自带实现Jdbc的类的实现方式后面实现完全自定义的方式。 3.1 自带的Jdbc实现类 从源码中我们知道其读取的接口分别是RegisteredClientRepository、OAuth2AuthorizationService和OAuth2AuthorizationConsentService。而这几个接口分别都有内存实现和数据库实现的类如下图以RegisteredClientRepository为例就可以看到有这2个实现类 3.2 使用自带的Jdbc实现 1既然Spring Security已经有其实现类那么我们实现数据库存储只需要将默认内存换成Jdbc方式只需要在SecurityConfig注入对应的Bean Bean public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate){return new JdbcRegisteredClientRepository(jdbcTemplate); }Bean public OAuth2AuthorizationService oAuth2AuthorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository){return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository); }Bean public OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository){return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository); }2需要创建对应的表并在yaml文件中配置数据库连接即可 其默认数据库存储都是基于传统的Jdbc方式进行的但是很多生产项目其实都会使用Mybatis等框架下面就基于mybatis-plus重新定义这几个Jdbc。 4 基于自定义数据库客户端 代码参考lesson04子模块该模块是一个自定义数据库客户端的授权服务器这一章还会利用lesson02子模块的oauth-client模块作为客户端演示 lesson04 前提条件本次演示我们先在mysql数据库创建oauth-study库并创建表oauth2_registered_client、oauth2_authorization和oauth2_authorization_consent三个表 1在mysql数据库创建oauth-study库并创建表oauth2_registered_client、oauth2_authorization和oauth2_authorization_consent三个表 2新建lesson04子模块其pom引入如下 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-oauth2-authorization-server/artifactId/dependency!-- lombok依赖用于get/set的简便--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency!-- mysql依赖用于连接mysql数据库--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!-- mybatis-plus依赖用于使用mybatis-plus--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-spring-boot3-starter/artifactId/dependency!-- pool2和druid依赖用于mysql连接池--dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!-- 解决java.time.Duration序列化问题--dependencygroupIdcom.fasterxml.jackson.datatype/groupIdartifactIdjackson-datatype-jsr310/artifactId/dependency!-- 解决jacketjson序列化包 --dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-cas/artifactId/dependency /dependencies3在entity包下自定义类SelfRegisteredClient、SelfOAuth2Authorization和SelfOAuth2AuthorizationConsent三个类分别对应数据库表之所以无法使用RegisteredClient、OAuth2Authorization和OAuth2AuthorizationConsent是因为这些类的属性并不与数据库字段一一对应同时有些字段序列化到数据库需要特殊处理因此需要自定义。(注意里面有些字段需要使用特殊TypeHandler处理在后面会附上这些特殊定义的TypeHandler TableName(oauth2_registered_client) Data public class SelfRegisteredClient implements Serializable {private String id;private String clientId;private Instant clientIdIssuedAt;private String clientSecret;private Instant clientSecretExpiresAt;private String clientName;TableField(typeHandler SetStringTypeHandler.class)private SetString clientAuthenticationMethods;TableField(typeHandler SetStringTypeHandler.class)private SetString authorizationGrantTypes;TableField(typeHandler SetStringTypeHandler.class)private SetString redirectUris;TableField(typeHandler SetStringTypeHandler.class)private SetString postLogoutRedirectUris;TableField(typeHandler SetStringTypeHandler.class)private SetString scopes;TableField(typeHandler ClientSettingsTypeHandler.class)private ClientSettings clientSettings;TableField(typeHandler TokenSettingsTypeHandler.class)private TokenSettings tokenSettings;public static RegisteredClient covertRegisteredClient(SelfRegisteredClient selfClient){if(selfClient!null){return RegisteredClient.withId(selfClient.getId()).clientId(selfClient.getClientId()).clientSecret(selfClient.getClientSecret()).clientName(selfClient.getClientName()).clientIdIssuedAt(selfClient.getClientIdIssuedAt()).clientSecretExpiresAt(selfClient.getClientSecretExpiresAt()).clientAuthenticationMethods(methods-{methods.addAll(SelfRegisteredClient.getMethodSetFromString(selfClient.getClientAuthenticationMethods()));}).authorizationGrantTypes(types-{types.addAll(SelfRegisteredClient.getSetTypeFromString(selfClient.getAuthorizationGrantTypes()));}).redirectUris(uris-{uris.addAll(selfClient.getRedirectUris());}).postLogoutRedirectUris(uris-{uris.addAll(selfClient.getPostLogoutRedirectUris());}).scopes(scopes1 -{scopes1.addAll(selfClient.getScopes());}).tokenSettings(selfClient.getTokenSettings()).clientSettings(selfClient.getClientSettings()).build();}return null;}public static SelfRegisteredClient covertSelfRegisteredClient(RegisteredClient client){if(client!null){SelfRegisteredClient selfRegisteredClient new SelfRegisteredClient();selfRegisteredClient.setId(client.getId());selfRegisteredClient.setClientId(client.getClientId());selfRegisteredClient.setClientSecret(client.getClientSecret());selfRegisteredClient.setClientName(client.getClientName());selfRegisteredClient.setClientAuthenticationMethods(getSetFromMethod(client.getClientAuthenticationMethods()));selfRegisteredClient.setAuthorizationGrantTypes(getSetFromType(client.getAuthorizationGrantTypes()));selfRegisteredClient.setRedirectUris(client.getRedirectUris());selfRegisteredClient.setPostLogoutRedirectUris(client.getPostLogoutRedirectUris());selfRegisteredClient.setScopes(client.getScopes());selfRegisteredClient.setClientSettings(client.getClientSettings());selfRegisteredClient.setTokenSettings(client.getTokenSettings());selfRegisteredClient.setClientIdIssuedAt(client.getClientIdIssuedAt());selfRegisteredClient.setClientSecretExpiresAt(client.getClientSecretExpiresAt());return selfRegisteredClient;}return null;}public static SetAuthorizationGrantType getSetTypeFromString(SetString strs){SetAuthorizationGrantType set new HashSet();if(strs!null !strs.isEmpty()){// 这里只是用目前OAuth2.1支持的类型原先的密码就不支持for(String authorizationGrantType : strs){AuthorizationGrantType type;if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {type AuthorizationGrantType.AUTHORIZATION_CODE;}else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {type AuthorizationGrantType.CLIENT_CREDENTIALS;}else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {type AuthorizationGrantType.REFRESH_TOKEN;}else{// Custom authorization grant typetype new AuthorizationGrantType(authorizationGrantType);}set.add(type);}}return set;}public static SetClientAuthenticationMethod getMethodSetFromString(SetString strs){SetClientAuthenticationMethod set new HashSet();if(strs!null !strs.isEmpty()){for(String method : strs){ClientAuthenticationMethod clientAuthenticationMethod;if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(method)) {clientAuthenticationMethod ClientAuthenticationMethod.CLIENT_SECRET_BASIC;}else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(method)) {clientAuthenticationMethod ClientAuthenticationMethod.CLIENT_SECRET_POST;}else if (ClientAuthenticationMethod.NONE.getValue().equals(method)) {clientAuthenticationMethod ClientAuthenticationMethod.NONE;}else {// Custom client authentication methodclientAuthenticationMethod new ClientAuthenticationMethod(method);}set.add(clientAuthenticationMethod);}}return set;}public static SetString getSetFromType(SetAuthorizationGrantType parameters){SetString set new HashSet();if(parameters!null){StringBuilder sb new StringBuilder();for(AuthorizationGrantType parameter : parameters){set.add(parameter.getValue());}}return set;}public static SetString getSetFromMethod(SetClientAuthenticationMethod parameters){SetString set new HashSet();if(parameters!null){StringBuilder sb new StringBuilder();for(ClientAuthenticationMethod parameter : parameters){set.add(parameter.getValue());}}return set;}}TableName(oauth2_authorization) Data public class SelfOAuth2Authorization implements Serializable {private String id;private String registeredClientId;private String principalName;private String authorizationGrantType;TableField(typeHandler SetStringTypeHandler.class)private SetString authorizedScopes;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object attributes;private String state;private String authorizationCodeValue;private Timestamp authorizationCodeIssuedAt;private Timestamp authorizationCodeExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object authorizationCodeMetadata;private String accessTokenValue;private Timestamp accessTokenIssuedAt;private Timestamp accessTokenExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object accessTokenMetadata;private String accessTokenType;TableField(typeHandler SetStringTypeHandler.class)private SetString accessTokenScopes;private String oidcIdTokenValue;private Timestamp oidcIdTokenIssuedAt;private Timestamp oidcIdTokenExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object oidcIdTokenMetadata;private String refreshTokenValue;private Timestamp refreshTokenIssuedAt;private Timestamp refreshTokenExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object refreshTokenMetadata;private String userCodeValue;private Timestamp userCodeIssuedAt;private Timestamp userCodeExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object userCodeMetadata;private String deviceCodeValue;private Timestamp deviceCodeIssuedAt;private Timestamp deviceCodeExpiresAt;TableField(typeHandler TokenMetadataTypeHandler.class)private MapString, Object deviceCodeMetadata;public static OAuth2Authorization covertOAuth2Authorization(SelfOAuth2Authorization selfOAuth2Authorization, RegisteredClientRepository registeredClientRepository){if(selfOAuth2Authorization!null){RegisteredClient registeredClient registeredClientRepository.findById(selfOAuth2Authorization.getRegisteredClientId());if (registeredClient null) {throw new DataRetrievalFailureException(The RegisteredClient with id selfOAuth2Authorization.getRegisteredClientId() was not found in the RegisteredClientRepository.);}OAuth2Authorization.Builder builder OAuth2Authorization.withRegisteredClient(registeredClient);builder.id(selfOAuth2Authorization.getId()).principalName(selfOAuth2Authorization.getPrincipalName()).authorizationGrantType(new AuthorizationGrantType(selfOAuth2Authorization.getAuthorizationGrantType())).authorizedScopes(selfOAuth2Authorization.getAuthorizedScopes()).attributes((attrs) - attrs.putAll(selfOAuth2Authorization.getAttributes()));String state selfOAuth2Authorization.getState();if (StringUtils.hasText(state)) {builder.attribute(OAuth2ParameterNames.STATE, state);}Instant tokenIssuedAt;Instant tokenExpiresAt;String authorizationCodeValue selfOAuth2Authorization.getAuthorizationCodeValue();if (StringUtils.hasText(authorizationCodeValue)) {tokenIssuedAt selfOAuth2Authorization.getAuthorizationCodeIssuedAt().toInstant();tokenExpiresAt selfOAuth2Authorization.getAuthorizationCodeExpiresAt().toInstant();MapString, Object authorizationCodeMetadata selfOAuth2Authorization.getAuthorizationCodeMetadata();OAuth2AuthorizationCode authorizationCode new OAuth2AuthorizationCode(authorizationCodeValue,tokenIssuedAt, tokenExpiresAt);builder.token(authorizationCode, (metadata) - metadata.putAll(authorizationCodeMetadata));}String accessTokenValue selfOAuth2Authorization.getAccessTokenValue();if (StringUtils.hasText(accessTokenValue)) {tokenIssuedAt selfOAuth2Authorization.getAccessTokenIssuedAt().toInstant();tokenExpiresAt selfOAuth2Authorization.getAccessTokenExpiresAt().toInstant();MapString, Object accessTokenMetadata selfOAuth2Authorization.getAccessTokenMetadata();OAuth2AccessToken.TokenType tokenType null;if (OAuth2AccessToken.TokenType.BEARER.getValue().equalsIgnoreCase(selfOAuth2Authorization.getAccessTokenType())) {tokenType OAuth2AccessToken.TokenType.BEARER;}SetString scopes selfOAuth2Authorization.getAccessTokenScopes();OAuth2AccessToken accessToken new OAuth2AccessToken(tokenType, accessTokenValue, tokenIssuedAt,tokenExpiresAt, scopes);builder.token(accessToken, (metadata) - metadata.putAll(accessTokenMetadata));}String oidcIdTokenValue selfOAuth2Authorization.getOidcIdTokenValue();if (StringUtils.hasText(oidcIdTokenValue)) {tokenIssuedAt selfOAuth2Authorization.getOidcIdTokenIssuedAt().toInstant();tokenExpiresAt selfOAuth2Authorization.getOidcIdTokenExpiresAt().toInstant();MapString, Object oidcTokenMetadata selfOAuth2Authorization.getOidcIdTokenMetadata();OidcIdToken oidcToken new OidcIdToken(oidcIdTokenValue, tokenIssuedAt, tokenExpiresAt,(MapString, Object) oidcTokenMetadata.get(OAuth2Authorization.Token.CLAIMS_METADATA_NAME));builder.token(oidcToken, (metadata) - metadata.putAll(oidcTokenMetadata));}String refreshTokenValue selfOAuth2Authorization.getRefreshTokenValue();if (StringUtils.hasText(refreshTokenValue)) {tokenIssuedAt selfOAuth2Authorization.getRefreshTokenIssuedAt().toInstant();tokenExpiresAt null;Timestamp refreshTokenExpiresAt selfOAuth2Authorization.getRefreshTokenExpiresAt();if (refreshTokenExpiresAt ! null) {tokenExpiresAt refreshTokenExpiresAt.toInstant();}MapString, Object refreshTokenMetadata selfOAuth2Authorization.getRefreshTokenMetadata();OAuth2RefreshToken refreshToken new OAuth2RefreshToken(refreshTokenValue, tokenIssuedAt,tokenExpiresAt);builder.token(refreshToken, (metadata) - metadata.putAll(refreshTokenMetadata));}String userCodeValue selfOAuth2Authorization.getUserCodeValue();if (StringUtils.hasText(userCodeValue)) {tokenIssuedAt selfOAuth2Authorization.getUserCodeIssuedAt().toInstant();tokenExpiresAt selfOAuth2Authorization.getUserCodeExpiresAt().toInstant();MapString, Object userCodeMetadata selfOAuth2Authorization.getUserCodeMetadata();OAuth2UserCode userCode new OAuth2UserCode(userCodeValue, tokenIssuedAt, tokenExpiresAt);builder.token(userCode, (metadata) - metadata.putAll(userCodeMetadata));}String deviceCodeValue selfOAuth2Authorization.getDeviceCodeValue();if (StringUtils.hasText(deviceCodeValue)) {tokenIssuedAt selfOAuth2Authorization.getDeviceCodeIssuedAt().toInstant();tokenExpiresAt selfOAuth2Authorization.getDeviceCodeExpiresAt().toInstant();MapString, Object deviceCodeMetadata selfOAuth2Authorization.getDeviceCodeMetadata();OAuth2DeviceCode deviceCode new OAuth2DeviceCode(deviceCodeValue, tokenIssuedAt, tokenExpiresAt);builder.token(deviceCode, (metadata) - metadata.putAll(deviceCodeMetadata));}return builder.build();}return null;}public static SelfOAuth2Authorization covertSelfOAuth2Authorization(OAuth2Authorization auth2Authorization){if(auth2Authorization!null){SelfOAuth2Authorization selfOAuth2Authorization new SelfOAuth2Authorization();selfOAuth2Authorization.setId(auth2Authorization.getId());selfOAuth2Authorization.setRegisteredClientId(auth2Authorization.getRegisteredClientId());selfOAuth2Authorization.setPrincipalName(auth2Authorization.getPrincipalName());selfOAuth2Authorization.setAuthorizationGrantType(auth2Authorization.getAuthorizationGrantType().getValue());selfOAuth2Authorization.setAuthorizedScopes(auth2Authorization.getAuthorizedScopes());selfOAuth2Authorization.setAttributes(auth2Authorization.getAttributes());String state null;String authorizationState auth2Authorization.getAttribute(OAuth2ParameterNames.STATE);if (StringUtils.hasText(authorizationState)) {state authorizationState;}selfOAuth2Authorization.setState(statenull?:state);OAuth2Authorization.TokenOAuth2AuthorizationCode authorizationCode auth2Authorization.getToken(OAuth2AuthorizationCode.class);if(authorizationCode!null){selfOAuth2Authorization.setAuthorizationCodeValue(authorizationCode.getToken().getTokenValue());selfOAuth2Authorization.setAuthorizationCodeIssuedAt(new Timestamp(authorizationCode.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setAuthorizationCodeExpiresAt(new Timestamp(authorizationCode.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setAuthorizationCodeMetadata(authorizationCode.getMetadata());}OAuth2Authorization.TokenOAuth2AccessToken accessToken auth2Authorization.getToken(OAuth2AccessToken.class);if (accessToken ! null) {selfOAuth2Authorization.setAccessTokenValue(accessToken.getToken().getTokenValue());selfOAuth2Authorization.setAccessTokenIssuedAt(new Timestamp(accessToken.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setAccessTokenExpiresAt(new Timestamp(accessToken.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setAccessTokenMetadata(accessToken.getMetadata());selfOAuth2Authorization.setAccessTokenType(accessToken.getToken().getTokenType().getValue());selfOAuth2Authorization.setAccessTokenScopes(accessToken.getToken().getScopes());}OAuth2Authorization.TokenOidcIdToken oidcIdToken auth2Authorization.getToken(OidcIdToken.class);if (oidcIdToken ! null) {selfOAuth2Authorization.setOidcIdTokenValue(oidcIdToken.getToken().getTokenValue());selfOAuth2Authorization.setOidcIdTokenIssuedAt(new Timestamp(oidcIdToken.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setOidcIdTokenExpiresAt(new Timestamp(oidcIdToken.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setOidcIdTokenMetadata(oidcIdToken.getMetadata());}OAuth2Authorization.TokenOAuth2RefreshToken refreshToken auth2Authorization.getRefreshToken();if (refreshToken ! null) {selfOAuth2Authorization.setRefreshTokenValue(refreshToken.getToken().getTokenValue());selfOAuth2Authorization.setRefreshTokenIssuedAt(new Timestamp(refreshToken.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setRefreshTokenExpiresAt(new Timestamp(refreshToken.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setRefreshTokenMetadata(refreshToken.getMetadata());}OAuth2Authorization.TokenOAuth2UserCode userCode auth2Authorization.getToken(OAuth2UserCode.class);if (userCode ! null) {selfOAuth2Authorization.setUserCodeValue(userCode.getToken().getTokenValue());selfOAuth2Authorization.setUserCodeIssuedAt(new Timestamp(userCode.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setUserCodeExpiresAt(new Timestamp(userCode.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setUserCodeMetadata(userCode.getMetadata());}OAuth2Authorization.TokenOAuth2DeviceCode deviceCode auth2Authorization.getToken(OAuth2DeviceCode.class);if (deviceCode ! null) {selfOAuth2Authorization.setDeviceCodeValue(deviceCode.getToken().getTokenValue());selfOAuth2Authorization.setDeviceCodeIssuedAt(new Timestamp(deviceCode.getToken().getIssuedAt().getEpochSecond()*1000));selfOAuth2Authorization.setDeviceCodeExpiresAt(new Timestamp(deviceCode.getToken().getExpiresAt().getEpochSecond()*1000));selfOAuth2Authorization.setDeviceCodeMetadata(deviceCode.getMetadata());}return selfOAuth2Authorization;}return null;} }TableName(oauth2_authorization_consent) Data public class SelfOAuth2AuthorizationConsent implements Serializable {private String registeredClientId;private String principalName;TableField(typeHandler SetStringTypeHandler.class)private SetString authorities;public static SelfOAuth2AuthorizationConsent convertSelfOAuth2AuthorizationConsent(OAuth2AuthorizationConsent auth2AuthorizationConsent){if(auth2AuthorizationConsent!null){SelfOAuth2AuthorizationConsent selfOAuth2AuthorizationConsent new SelfOAuth2AuthorizationConsent();selfOAuth2AuthorizationConsent.setRegisteredClientId(auth2AuthorizationConsent.getRegisteredClientId());selfOAuth2AuthorizationConsent.setPrincipalName(auth2AuthorizationConsent.getPrincipalName());if(auth2AuthorizationConsent.getAuthorities()!null){selfOAuth2AuthorizationConsent.setAuthorities(auth2AuthorizationConsent.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()));}return selfOAuth2AuthorizationConsent;}return null;}public static OAuth2AuthorizationConsent convertOAuth2AuthorizationConsent(SelfOAuth2AuthorizationConsent selfOAuth2AuthorizationConsent, RegisteredClientRepository registeredClientRepository){if(selfOAuth2AuthorizationConsent!null){RegisteredClient registeredClient registeredClientRepository.findById(selfOAuth2AuthorizationConsent.getRegisteredClientId());if (registeredClient null) {throw new DataRetrievalFailureException(The RegisteredClient with id selfOAuth2AuthorizationConsent.getRegisteredClientId() was not found in the RegisteredClientRepository.);}OAuth2AuthorizationConsent.Builder builder OAuth2AuthorizationConsent.withId(selfOAuth2AuthorizationConsent.getRegisteredClientId(),selfOAuth2AuthorizationConsent.getPrincipalName());for (String authority : selfOAuth2AuthorizationConsent.getAuthorities()) {builder.authority(new SimpleGrantedAuthority(authority));}return builder.build();}return null;} } 4在mapper包下自定义Mapper读取oauth2_registered_client 表 Mapper public interface Oauth2RegisteredClientMapper extends BaseMapperSelfRegisteredClient {// 根据client_id查询客户端信息Select(select * from oauth2_registered_client where client_id #{client_id})SelfRegisteredClient selectByClientId(String client_id); }Mapper public interface OAuth2AuthorizationMapper extends BaseMapperSelfOAuth2Authorization { }Mapper public interface OAuth2AuthorizationConsentMapper extends BaseMapperSelfOAuth2AuthorizationConsent { }5在handler包下自定义某些字段存储到库的TypeHandler。这是由于三个表中有几个字段需要特殊存储因此需要自定义TypeHandler MappedJdbcTypes({JdbcType.VARCHAR}) //对应数据库类型 MappedTypes({ClientSettings.class}) //java数据类型 public class ClientSettingsTypeHandler implements TypeHandlerClientSettings {private ObjectMapper objectMapper;public ClientSettingsTypeHandler() {objectMapper new ObjectMapper();/*** 此处注册json存储格式化*/ClassLoader classLoader ClientSettingsTypeHandler.class.getClassLoader();ListModule securityModules SecurityJackson2Modules.getModules(classLoader);this.objectMapper.registerModules(securityModules);this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());}Overridepublic void setParameter(PreparedStatement ps, int i, ClientSettings parameter, JdbcType jdbcType) throws SQLException {if(parameter!nullparameter.getSettings()!null){ps.setString(i ,writeMap(parameter.getSettings()));}else{ps.setString(i, );}}Overridepublic ClientSettings getResult(ResultSet rs, String columnName) throws SQLException {String str rs.getString(columnName);return ClientSettings.withSettings(parseMap(str)).build();}Overridepublic ClientSettings getResult(ResultSet rs, int columnIndex) throws SQLException {String str rs.getString(columnIndex);return ClientSettings.withSettings(parseMap(str)).build();}Overridepublic ClientSettings getResult(CallableStatement cs, int columnIndex) throws SQLException {String str cs.getString(columnIndex);return ClientSettings.withSettings(parseMap(str)).build();}private String writeMap(MapString, Object data) {try {return this.objectMapper.writeValueAsString(data);}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}private MapString, Object parseMap(String data) {if(data!null!data.isEmpty()){try {return this.objectMapper.readValue(data, new TypeReferenceMapString, Object() {});}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}else{return new HashMap();}} }MappedJdbcTypes({JdbcType.VARCHAR}) //对应数据库类型 MappedTypes({Set.class}) //java数据类型 public class SetStringTypeHandler implements TypeHandlerSetString {private static final String COMMA ,;Overridepublic void setParameter(PreparedStatement ps, int i, SetString parameters, JdbcType jdbcType) throws SQLException {String str ;if(parameters!null){str String.join(COMMA, parameters);}ps.setString(i, str);}Overridepublic SetString getResult(ResultSet rs, String columnName) throws SQLException {String str rs.getString(columnName);return getSetFromString(str);}Overridepublic SetString getResult(ResultSet rs, int columnIndex) throws SQLException {String str rs.getString(columnIndex);return getSetFromString(str);}Overridepublic SetString getResult(CallableStatement cs, int columnIndex) throws SQLException {String str cs.getString(columnIndex);return getSetFromString(str);}private SetString getSetFromString(String str){SetString set new HashSet();if(str!null !str.isEmpty()){String[] strs str.split(COMMA);Collections.addAll(set, strs);}return set;} }MappedJdbcTypes({JdbcType.BLOB}) //对应数据库类型 MappedTypes({Map.class}) public class TokenMetadataTypeHandler implements TypeHandlerMapString, Object {private ObjectMapper objectMapper;public TokenMetadataTypeHandler() {objectMapper new ObjectMapper();/*** 此处注册json存储格式化*/ClassLoader classLoader TokenMetadataTypeHandler.class.getClassLoader();ListModule securityModules SecurityJackson2Modules.getModules(classLoader);this.objectMapper.registerModules(securityModules);this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());}Overridepublic void setParameter(PreparedStatement ps, int i, MapString, Object parameter, JdbcType jdbcType) throws SQLException {if(parameter!null){ps.setString(i ,writeMap(parameter));}else{ps.setString(i, );}}Overridepublic MapString, Object getResult(ResultSet rs, String columnName) throws SQLException {String str rs.getString(columnName);return parseMap(str);}Overridepublic MapString, Object getResult(ResultSet rs, int columnIndex) throws SQLException {String str rs.getString(columnIndex);return parseMap(str);}Overridepublic MapString, Object getResult(CallableStatement cs, int columnIndex) throws SQLException {String str cs.getString(columnIndex);return parseMap(str);}private String writeMap(MapString, Object data) {try {this.objectMapper.findAndRegisterModules();return this.objectMapper.writeValueAsString(data);}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}private MapString, Object parseMap(String data) {if(data!null!data.isEmpty()){try {return this.objectMapper.readValue(data, new TypeReferenceMapString, Object() {});}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}else{return new HashMap();}} }MappedJdbcTypes({JdbcType.VARCHAR}) //对应数据库类型 MappedTypes({TokenSettings.class}) //java数据类型 public class TokenSettingsTypeHandler implements TypeHandlerTokenSettings {private ObjectMapper objectMapper;public TokenSettingsTypeHandler() {objectMapper new ObjectMapper();/*** 此处注册json存储格式化*/ClassLoader classLoader TokenSettingsTypeHandler.class.getClassLoader();ListModule securityModules SecurityJackson2Modules.getModules(classLoader);this.objectMapper.registerModules(securityModules);this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());}Overridepublic void setParameter(PreparedStatement ps, int i, TokenSettings parameter, JdbcType jdbcType) throws SQLException {if(parameter!nullparameter.getSettings()!null){ps.setString(i ,writeMap(parameter.getSettings()));}else{ps.setString(i, );}}Overridepublic TokenSettings getResult(ResultSet rs, String columnName) throws SQLException {String str rs.getString(columnName);return TokenSettings.withSettings(parseMap(str)).build();}Overridepublic TokenSettings getResult(ResultSet rs, int columnIndex) throws SQLException {String str rs.getString(columnIndex);return TokenSettings.withSettings(parseMap(str)).build();}Overridepublic TokenSettings getResult(CallableStatement cs, int columnIndex) throws SQLException {String str cs.getString(columnIndex);return TokenSettings.withSettings(parseMap(str)).build();}private String writeMap(MapString, Object data) {try {this.objectMapper.findAndRegisterModules();return this.objectMapper.writeValueAsString(data);}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}private MapString, Object parseMap(String data) {if(data!null!data.isEmpty()){try {MapString, Object map this.objectMapper.readValue(data, new TypeReferenceMapString, Object() {});return map;}catch (Exception ex) {throw new IllegalArgumentException(ex.getMessage(), ex);}}else{return new HashMap();}} }6在repository包下自定义SelfJdbcRegisteredClientRepository、SelfJdbcOAuth2AuthorizationService和SeltJdbcOAuth2AuthorizationConsentService Repository public class SelfJdbcRegisteredClientRepository implements RegisteredClientRepository {AutowiredOauth2RegisteredClientMapper mapper;Overridepublic void save(RegisteredClient registeredClient) {Assert.notNull(registeredClient, registeredClient cannot be null);SelfRegisteredClient existingRegisteredClient this.mapper.selectById(registeredClient.getId());if (existingRegisteredClient ! null) {this.mapper.updateById(SelfRegisteredClient.covertSelfRegisteredClient(registeredClient));}else {this.mapper.insert(SelfRegisteredClient.covertSelfRegisteredClient(registeredClient));}}Overridepublic RegisteredClient findById(String id) {return SelfRegisteredClient.covertRegisteredClient(this.mapper.selectById(id));}Overridepublic RegisteredClient findByClientId(String clientId) {return SelfRegisteredClient.covertRegisteredClient(this.mapper.selectByClientId(clientId));}private void updateRegisteredClient(RegisteredClient registeredClient) {this.mapper.updateById(SelfRegisteredClient.covertSelfRegisteredClient(registeredClient));}}Service public class SelfJdbcOAuth2AuthorizationService implements OAuth2AuthorizationService {Autowiredprivate RegisteredClientRepository registeredClientRepository;Autowiredprivate OAuth2AuthorizationMapper oAuth2AuthorizationMapper;Overridepublic void save(OAuth2Authorization authorization) {Assert.notNull(authorization, authorization cannot be null);OAuth2Authorization existingAuthorization findById(authorization.getId());if (existingAuthorization null) {oAuth2AuthorizationMapper.insert(SelfOAuth2Authorization.covertSelfOAuth2Authorization(authorization));}else {oAuth2AuthorizationMapper.updateById(SelfOAuth2Authorization.covertSelfOAuth2Authorization(authorization));}}Overridepublic void remove(OAuth2Authorization authorization) {oAuth2AuthorizationMapper.deleteById(SelfOAuth2Authorization.covertSelfOAuth2Authorization(authorization));}Overridepublic OAuth2Authorization findById(String id) {SelfOAuth2Authorization selfOAuth2Authorization oAuth2AuthorizationMapper.selectById(id);return SelfOAuth2Authorization.covertOAuth2Authorization(selfOAuth2Authorization, registeredClientRepository);}Overridepublic OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {Assert.hasText(token, token cannot be empty);ListSqlParameterValue parameters new ArrayList();ListSelfOAuth2Authorization result null;MapString, Object map new HashMap();if (tokenType null) {map.put(state, token);byte[] tokenBytes token.getBytes(StandardCharsets.UTF_8);map.put(authorization_code_value, tokenBytes);map.put(access_token_value, tokenBytes);map.put(oidc_id_token_value, tokenBytes);map.put(refresh_token_value, tokenBytes);map.put(user_code_value, tokenBytes);map.put(device_code_value, tokenBytes);result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {map.put(state, token);result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {map.put(authorization_code_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2TokenType.ACCESS_TOKEN.equals(tokenType)) {map.put(access_token_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}else if (OidcParameterNames.ID_TOKEN.equals(tokenType.getValue())) {map.put(oidc_id_token_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2TokenType.REFRESH_TOKEN.equals(tokenType)) {map.put(refresh_token_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2ParameterNames.USER_CODE.equals(tokenType.getValue())) {map.put(user_code_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}else if (OAuth2ParameterNames.DEVICE_CODE.equals(tokenType.getValue())) {map.put(device_code_value, token.getBytes(StandardCharsets.UTF_8));result oAuth2AuthorizationMapper.selectByMap(map);}return result!null!result.isEmpty()?SelfOAuth2Authorization.covertOAuth2Authorization(result.get(0),registeredClientRepository):null;} }Service public class SeltJdbcOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {Autowiredprivate OAuth2AuthorizationConsentMapper auth2AuthorizationConsentMapper;Autowiredprivate RegisteredClientRepository registeredClientRepository;Overridepublic void save(OAuth2AuthorizationConsent authorizationConsent) {Assert.notNull(authorizationConsent, authorizationConsent cannot be null);OAuth2AuthorizationConsent existingAuthorizationConsent findById(authorizationConsent.getRegisteredClientId(),authorizationConsent.getPrincipalName());if (existingAuthorizationConsent null) {auth2AuthorizationConsentMapper.insert(SelfOAuth2AuthorizationConsent.convertSelfOAuth2AuthorizationConsent(authorizationConsent));}else {auth2AuthorizationConsentMapper.updateById(SelfOAuth2AuthorizationConsent.convertSelfOAuth2AuthorizationConsent(authorizationConsent));}}Overridepublic void remove(OAuth2AuthorizationConsent authorizationConsent) {auth2AuthorizationConsentMapper.deleteById(SelfOAuth2AuthorizationConsent.convertSelfOAuth2AuthorizationConsent(authorizationConsent));}Overridepublic OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {MapString, Object map new HashMap();map.put(registered_client_id, registeredClientId);map.put(principal_name, principalName);ListSelfOAuth2AuthorizationConsent list auth2AuthorizationConsentMapper.selectByMap(map);return listnull||list.isEmpty()?null:SelfOAuth2AuthorizationConsent.convertOAuth2AuthorizationConsent(list.get(0), registeredClientRepository);}}7在config包下配置SecurityConfig这个和lesson03子模块很像去除自定义授权页定义即可 Configuration public class SecurityConfig {// 自定义授权服务器的Filter链BeanOrder(Ordered.HIGHEST_PRECEDENCE)SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)// oidc配置.oidc(withDefaults());// 资源服务器默认jwt配置http.oauth2ResourceServer((resourceServer) - resourceServer.jwt(withDefaults()));// 异常处理http.exceptionHandling((exceptions) - exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(/login)));return http.build();}// 自定义Spring Security的链路。如果自定义授权服务器的Filter链则原先自动化配置将会失效因此也要配置Spring SecurityBeanOrder(SecurityProperties.BASIC_AUTH_ORDER)SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((authorize) - authorize.requestMatchers(/demo, /test).permitAll().anyRequest().authenticated()).formLogin(withDefaults());return http.build();}}8在resources包下配置化application.yml文件注意要在mybatis-plus配置下注册ypeHandler server:port: 9000logging:level:org.springframework.security: tracespring:security:# 使用security配置授权服务器的登录用户和密码user:name: userpassword: 1234# 配置数据源datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/oauth_study?serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf-8zeroDateTimeBehaviorconvertToNulluseSSLfalseallowPublicKeyRetrievaltrueusername: rootpassword: rootdruid:initial-size: 5min-idle: 5maxActive: 20maxWait: 3000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: select xtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: falsefilters: stat,wall,slf4jconnectionProperties: druid.stat.mergeSqltrue;druid.stat.slowSqlMillis5000;socketTimeout10000;connectTimeout1200# mybatis-plus的配置 mybatis-plus:global-config:banner: falsemapper-locations: classpath:mappers/*.xmltype-aliases-package: com.demo.lesson04.entity# 将handler包下的TypeHandler注册进去type-handlers-package: com.demo.lesson04.handlerconfiguration:cache-enabled: falselocal-cache-scope: statement9在controller包下定义InsertController通过接口方式注册一个和lesson03一样信息的客户端 RestController public class InsertController{AutowiredOauth2RegisteredClientMapper oauth2RegisteredClientMapper;GetMapping(/insert)public void insert(){SelfRegisteredClient client new SelfRegisteredClient();client.setId(UUID.randomUUID().toString());client.setClientId(oidc-client);client.setClientSecret({noop}secret);client.setClientName(oidc-client);SetClientAuthenticationMethod methodSet new HashSet();client.setClientAuthenticationMethods(new HashSet(Collections.singleton(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())));SetString typeSet new HashSet();typeSet.add(AuthorizationGrantType.AUTHORIZATION_CODE.getValue());typeSet.add(AuthorizationGrantType.REFRESH_TOKEN.getValue());client.setAuthorizationGrantTypes(typeSet);client.setRedirectUris(new HashSet(Collections.singleton(http://localhost:8080/login/oauth2/code/oidc-client)));client.setPostLogoutRedirectUris(new HashSet(Collections.singleton(http://localhost:8080/)));SetString scopeSet new HashSet();scopeSet.add(OidcScopes.OPENID);scopeSet.add(OidcScopes.PROFILE);client.setScopes(scopeSet);client.setClientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build());client.setTokenSettings(TokenSettings.builder().build());oauth2RegisteredClientMapper.insert(client);System.out.println(client);} }10新建启动类Oauth2Lesson04Application并启动 SpringBootApplication public class Oauth2Lesson04Application {public static void main(String[] args) {SpringApplication.run(Oauth2Lesson04Application.class, args);} }11启动lesson02子模块的oauth-client子模块作为演示客户端 12插入客户端访问http://localhost:9000/insert 插入一个客户端其实就是把原先在yaml配置的客户端插入到数据库。我们会看到数据库表oauth_study.oauth2_registered_client插入一条记录 13测试访问http://localhost:8080/demo 你就可以看到与《系列之四 - 客户端–oauth2-client底层原理》一样的流程只不过其客户端信息是在数据库中你可以一步一步操作看看数据库三张表数据的变化。 结语在本章及之前章节我们对Spring Security实现OAuth2做了一个基本了解也通过自定义授权页面、自定义数据库客户端信息等窥探了Spring Authrization Server下一章我们将会讲述Spring Authrization Server的关键原理代码以及一些关键的Filter这样对我们后面做更高级的配置有一个很好的了解。
http://www.dnsts.com.cn/news/90924.html

相关文章:

  • 赤水市住房和城乡建设局网站做文交所的都有哪些网站
  • 室内装饰网站模板济南手机网站开发公司
  • 怎么做游戏充值代理网站做网站费用需要分摊吗
  • 有FTP免费网站辽宁省建设工程信息网招标
  • 朝阳网站建设推广北京网页制作案例
  • 宝应网站设计嘉兴网站建设模板网站
  • 网页素材网站有哪些dede淘宝客网站模板
  • 网站免费下载安装玉山电商网站建设
  • 典型的网站开发人员急招土建施工员技术员
  • 做书的网站有哪些内容广东佛山网站建设
  • 2016网站设计风格做艺术教育的网站
  • lnmp网站开发产权交易中心网站建设的原因
  • 承德网站建设作用郑州 中原区
  • 注册域名之后怎么做网站汽车网站建设方案预算
  • 做网站商城赔了8万win7如何建设免费网站
  • 手机免费网站建设网站如何防止重登录
  • 淘宝基地网站怎么做wordpress d8 4.0
  • 阿里云建wordpress站免费外贸电商平台
  • 电商网站建设策划方案自己建网站难吗
  • dedecms5.7 财经网站盐城做网站网络公司电话?
  • 编程网站免费中文版博客网站 做淘宝客
  • 做网站窗体属性栏设置文字居中企业logo图片
  • 做纺织机械的网站域名杭州有哪些软件公司
  • 东坑网站仿做北京现在可以自由出入吗
  • 电子商务网站规划的流程wordpress如何修改登录地址
  • 企业网站制作教程视频智慧团建官网手机版登录
  • 企业网站备案收费网络营销和网络推广
  • 网站建设佰金手指科杰二八软件商店下载安装app
  • 网站建设前期应该做哪些准备课程网站开发的研究现状
  • 江苏省省建设集团网站html教程电子书