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

做设计兼职的网站有哪些工作网站开发费分摊多少年

做设计兼职的网站有哪些工作,网站开发费分摊多少年,成都招聘网站建设,昆明自助建站软件前言 注意#xff1a;我本地没有生成公钥和私钥#xff0c;所以每次启动项目jwkSource都会重新生成#xff0c;导致之前认证的token都会失效#xff0c;具体如何生成私钥和公钥以及怎么配置到授权服务器中#xff0c;网上有很多方法自行实现即可 之前有个项目用的0.0.3的…前言 注意我本地没有生成公钥和私钥所以每次启动项目jwkSource都会重新生成导致之前认证的token都会失效具体如何生成私钥和公钥以及怎么配置到授权服务器中网上有很多方法自行实现即可 之前有个项目用的0.0.3的正好最近想研究研究所以就去了官网看文档研究了一下1.1.1基于的事security6.x的版本, security6与5.7之前的版本有很大的差别废话不多说直接上代码(代码中也有一些注释) 最基础的配置官网都有这里不去体现主要体现功能 自定义认证和授权自定义端点拦截器持久化到数据库 版本 依赖项版本springboot3.1.2spring-authorization-server1.1.1jdk17dynamic-datasource-spring-boot3-starter4.1.2mybatis-plus3.5.3 sql文件 代码实操 目录结构 pom文件 需要额外引入spring security cas包原因是启动时(logging等级org.springframework.security: trace)会报错java.lang.ClassNotFoundException:org.springframework.security.cas.jackson2.CasJackson2Module错误。 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.1.2/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.example/groupIdartifactIddemo/artifactIdversion0.0.1-SNAPSHOT/versionnamedemo/namedescriptiondemo/descriptionpropertiesjava.version17/java.version/propertiesdependencyManagement !-- dependencies-- !-- lt;!ndash; SpringBoot的依赖配置ndash;gt;-- !-- dependency-- !-- groupIdorg.springframework.boot/groupId-- !-- artifactIdspring-boot-dependencies/artifactId-- !-- version2.5.14/version-- !-- typepom/type-- !-- scopeimport/scope-- !-- /dependency-- !-- /dependencies--/dependencyManagementdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-oauth2-authorization-server/artifactId/dependency!-- 添加spring security cas支持这里需添加spring-security-cas依赖否则启动时报java.lang.ClassNotFoundException: org.springframework.security.cas.jackson2.CasJackson2Module错误。--dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-cas/artifactId/dependencydependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactIdversion2.0.34/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.3/version/dependency!-- 阿里数据库连接池 --dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.2.16/version/dependency!-- SpringBoot Web容器 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.31/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jdbc/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot3-starter/artifactIdversion4.1.2/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/plugins/build/project 授权服务器配置包名authenticationServer CustomAuthorizationServerConfiguration import com.example.demo.config.security.provider.WeChatMiniAppAuthenticationProvider; import com.example.demo.config.security.provider.converter.WeChatMiniAppAuthenticationConverter; import com.example.demo.utils.OAuth2ConfigurerUtils; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientCredentialsAuthenticationConverter; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2RefreshTokenAuthenticationConverter; import org.springframework.security.web.util.matcher.RequestMatcher;public class CustomAuthorizationServerConfiguration {public static void applyDefaultSecurity(HttpSecurity http, JWKSourceSecurityContext jwkSource) throws Exception {OAuth2AuthorizationServerConfigurer authorizationServerConfigurer new OAuth2AuthorizationServerConfigurer();OAuth2AuthorizationService authorizationService OAuth2ConfigurerUtils.getBean(http,OAuth2AuthorizationService.class);// 认证过滤器链authorizationServerConfigurer.tokenEndpoint(oAuth2TokenEndpointConfigurer - {oAuth2TokenEndpointConfigurer.accessTokenRequestConverters( customJwtAuthenticationToken - {customJwtAuthenticationToken.add(new OAuth2AuthorizationCodeAuthenticationConverter());customJwtAuthenticationToken.add(new OAuth2RefreshTokenAuthenticationConverter());customJwtAuthenticationToken.add(new OAuth2ClientCredentialsAuthenticationConverter());customJwtAuthenticationToken.add(new WeChatMiniAppAuthenticationConverter());})// 返回accessToken的后置处理器 https://docs.spring.io/spring-authorization-server/docs/current/reference/html/protocol-endpoints.html#oauth2-token-endpoint // .accessTokenResponseHandler()// 异常返回处理器 // .errorResponseHandler().authenticationProviders((customProviders) - {// 自定义认证提供者customProviders.add(new WeChatMiniAppAuthenticationProvider(jwkSource,authorizationService));});});// 端点匹配器RequestMatcher endpointsMatcher authorizationServerConfigurer.getEndpointsMatcher();http.securityMatcher(endpointsMatcher)// .authorizeHttpRequests(authorizeRequests - authorizeRequests.anyRequest().authenticated())// csrf.csrf(csrf - csrf.ignoringRequestMatchers(endpointsMatcher)).apply(authorizationServerConfigurer);}}认证提供者(包名provider) 预处理包名 Converter WeChatMiniAppAuthenticationConverter 可以说是预处理类转换token信息 import com.example.demo.config.security.provider.token.WeChatMiniAppAuthenticationToken; import com.example.demo.config.security.provider.type.AuthorizationGrantTypes; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap;import java.util.LinkedHashMap; import java.util.Map;public final class WeChatMiniAppAuthenticationConverter implements AuthenticationConverter {private final Logger logger LoggerFactory.getLogger(WeChatMiniAppAuthenticationConverter.class);/*** 参数对象** param request {link HttpServletRequest}* return {link Authentication}*/Overridepublic Authentication convert(HttpServletRequest request) {String grantType request.getParameter(OAuth2ParameterNames.GRANT_TYPE);if (!AuthorizationGrantTypes.WECHAT_MINIAPP.getValue().equals(grantType)) {return null;}// 获取参数MultiValueMapString, String parameters getParameters(request);logger.info(微信小程序授权入参{}, parameters);// 微信CODE// 其他参数MapString, Object additionalParameters getOtherParameters(parameters);// clientPrincipalAuthentication clientPrincipal SecurityContextHolder.getContext().getAuthentication();logger.info(小程序授权全部参数{}, additionalParameters);return new WeChatMiniAppAuthenticationToken(clientPrincipal, additionalParameters, code,appid, encryptedData, ivStr);}/*** 获取其他参数** param parameters {link MultiValueMap}* return {link Map}*/private MapString, Object getOtherParameters(MultiValueMapString, String parameters) {MapString, Object additionalParameters new LinkedHashMap(16);parameters.forEach((key, value) - {if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) !key.equals(OAuth2ParameterNames.SCOPE)) {additionalParameters.put(key, value.get(0));}});return additionalParameters;}static MultiValueMapString, String getParameters(HttpServletRequest request) {MapString, String[] parameterMap request.getParameterMap();MultiValueMapString, String parameters new LinkedMultiValueMap(parameterMap.size());parameterMap.forEach((key, values) - {for (String value : values) {parameters.add(key, value);}});return parameters;}}自定义token 包名 token WeChatMiniAppAuthenticationToken Setter Getter public class WeChatMiniAppAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {/*** appId 应用ID*/private final String appId;/*** code 小程序CODE*/private final String code;private final String encryptedData;private final String ivStr;/*** Sub-class constructor.* param clientPrincipal the authenticated client principal* param additionalParameters the additional parameters* param code {link String } 小程序code* param appId {link String } 平台appid* param encryptedData {link String } encryptedData* param ivStr {link String } ivStr*/public WeChatMiniAppAuthenticationToken(Authentication clientPrincipal,MapString, Object additionalParameters, String code,String appId, String encryptedData, String ivStr) {super(AuthorizationGrantTypes.WECHAT_MINIAPP, clientPrincipal, additionalParameters);this.code code;this.appId appId;this.encryptedData encryptedData;this.ivStr ivStr;} }定义认证type (包名type) AuthorizationGrantTypes 人获取access_token时会用到grantType public class AuthorizationGrantTypes {public static final AuthorizationGrantType WECHAT_MINIAPP new AuthorizationGrantType(wechat_miniapp);} 资源服务器 包名resourceServer CustomAuthenticationTokenConverter 自定义jwt 预处理器 public class CustomAuthenticationToken implements ConverterJwt, AbstractAuthenticationToken {private final ConverterJwt, CollectionGrantedAuthority jwtGrantedAuthoritiesConverter new JwtGrantedAuthoritiesConverter();private static final String PRINCIPAL_CLAIM_NAME data;private final Logger logger LoggerFactory.getLogger(CustomAuthenticationToken.class);public CustomAuthenticationToken() {}public AbstractAuthenticationToken convert(NonNull Jwt jwt) {this.logger.info(convert -jwt:{}, JSONObject.toJSONString(jwt));CollectionGrantedAuthority authorities this.extractAuthorities(jwt);// 获取个性化的token信息String principalClaimValue jwt.getClaimAsString(PRINCIPAL_CLAIM_NAME);if (principalClaimValue null) {return new JwtAuthenticationToken(jwt, authorities);} else {UserDto user this.extractUserInfo(jwt);user.setToken(jwt.getTokenValue());CustomJwtAuthenticationToken jwtAuthenticationToken new CustomJwtAuthenticationToken(jwt, user, authorities);SecurityContextHolder.getContext().setAuthentication(jwtAuthenticationToken);return jwtAuthenticationToken;}}protected CollectionGrantedAuthority extractAuthorities(Jwt jwt) {return this.jwtGrantedAuthoritiesConverter.convert(jwt);}protected UserDto extractUserInfo(Jwt jwt) {String principalClaimValue jwt.getClaimAsString(data);return JSONObject.parseObject(principalClaimValue, UserDto.class);} }CustomJwtAuthenticationToken 自定义的jwt Transient public class CustomJwtAuthenticationToken extends AbstractOAuth2TokenAuthenticationTokenJwt {private static final long serialVersionUID 560L;private final String name;public CustomJwtAuthenticationToken(Jwt jwt, Object principal, Collection? extends GrantedAuthority authorities) {super(jwt, principal, , authorities);this.setAuthenticated(true);this.name jwt.getSubject();}public MapString, Object getTokenAttributes() {return ((Jwt)this.getToken()).getClaims();}public String getName() {return this.name;} }CustomOauth2AuthenticationEntryPoint 自定义协议端点 public class CustomOauth2AuthenticationEntryPoint implements AuthenticationEntryPoint {private static final Logger logger LoggerFactory.getLogger(CustomOauth2AuthenticationEntryPoint.class);private String realmName;public CustomOauth2AuthenticationEntryPoint() {}public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {logger.error(e.getLocalizedMessage(), e);HttpStatus status HttpStatus.UNAUTHORIZED;MapString, String parameters new LinkedHashMap();if (Objects.nonNull(this.realmName)) {parameters.put(realm, this.realmName);}if (e instanceof OAuth2AuthenticationException oAuth2AuthenticationException) {OAuth2Error error oAuth2AuthenticationException.getError();parameters.put(error, error.getErrorCode());if (StringUtils.hasText(error.getDescription())) {String errorMessage error.getDescription();parameters.put(error_description, errorMessage);}if (StringUtils.hasText(error.getUri())) {parameters.put(error_uri, error.getUri());}if (error instanceof BearerTokenError bearerTokenError) {if (StringUtils.hasText(bearerTokenError.getScope())) {parameters.put(scope, bearerTokenError.getScope());}status ((BearerTokenError)error).getHttpStatus();}}ResponseEntityString unauthenticated new ResponseEntityString(Unauthenticated, HttpStatusCode.valueOf(status.value()));String message JSON.toJSONString(unauthenticated);String wwwAuthenticate WwwAuthenticateHeaderBuilder.computeWwwAuthenticateHeaderValue(parameters);response.addHeader(WWW-Authenticate, wwwAuthenticate);response.setStatus(status.value());response.setContentType(application/json);response.getWriter().write(message);} }WwwAuthenticateHeaderBuilder public final class WwwAuthenticateHeaderBuilder {public WwwAuthenticateHeaderBuilder() {}public static String computeWwwAuthenticateHeaderValue(MapString, String parameters) {StringJoiner wwwAuthenticate new StringJoiner(, , Bearer , );if (!parameters.isEmpty()) {parameters.forEach((k, v) - {wwwAuthenticate.add(k \ v \);});}return wwwAuthenticate.toString();} }Oauth2ResourceServerConfigurer 资源服务器配置 public final class Oauth2ResourceServerConfigurer {public Oauth2ResourceServerConfigurer() {}public static void applyDefaultSecurity(HttpSecurity http) throws Exception {http.oauth2ResourceServer((oauth2ResourceServerConfigurer) -oauth2ResourceServerConfigurer// 无权限处理器 // .accessDeniedHandler()// 自定义协议端点.authenticationEntryPoint(new CustomOauth2AuthenticationEntryPoint()).jwt((jwtConfigurer) - jwtConfigurer.jwtAuthenticationConverter(new CustomAuthenticationToken())));} }SecurityConfig 实现授权及资源服务器 package com.example.demo.config.security;import com.example.demo.config.security.authenticationServer.CustomAuthorizationServerConfiguration; import com.example.demo.config.security.resourceServer.Oauth2ResourceServerConfigurer; import com.example.demo.service.CustomUserDetailsService; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.ImmutableJWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.jdbc.core.JdbcTemplate; 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.configurers.AbstractHttpConfigurer; 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.jackson2.CoreJackson2Module; import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.oauth2.core.*; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.server.authorization.*; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; import org.springframework.security.oauth2.server.authorization.token.*; import org.springframework.security.web.SecurityFilterChain;import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.time.Duration; import java.util.UUID;/***** author qb* since 2023/7/21 15:14* version 1.0*/ Slf4j Configuration EnableWebSecurity public class SecurityConfig {// 协议端点过滤器链BeanOrder(1)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {CustomAuthorizationServerConfiguration.applyDefaultSecurity(http,jwkSource()); // // 开启oidc connect 1.0 // http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults()); // // 重定向到未通过身份验证的登录页面 授权终结点 // http.exceptionHandling((exceptions) - exceptions.defaultAuthenticationEntryPointFor( // new LoginUrlAuthenticationEntryPoint(/login), // new MediaTypeRequestMatcher(MediaType.TEXT_HTML) // )) // // 授权服务 接受的用户信息和/或客户端注册的访问令牌 // .oauth2ResourceServer((resourceServer) - resourceServer.jwt(Customizer.withDefaults()));return http.build();}// 协议认证筛选器BeanOrder(2)public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {Oauth2ResourceServerConfigurer.applyDefaultSecurity(http);http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(auth -auth.requestMatchers(/login,/callback,/oauth2/client/**).permitAll().anyRequest().authenticated());return http.build();}// 自定义认证serviceBeanpublic UserDetailsService userDetailsService() {return new CustomUserDetailsService();}// 密码加密Beanpublic PasswordEncoder passwordEncoder(){ // return PasswordEncoderFactories.createDelegatingPasswordEncoder();return new BCryptPasswordEncoder();}/*** 管理客户端* return /*/Beanpublic RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) { // RegisteredClient oidcClient defaultClient();// 配置模式 // JdbcRegisteredClientRepository jdbcRegisteredClientRepository new JdbcRegisteredClientRepository(jdbcTemplate); // if (null jdbcRegisteredClientRepository.findByClientId(client)) { // jdbcRegisteredClientRepository.save(oidcClient); // }return new JdbcRegisteredClientRepository(jdbcTemplate);}private static RegisteredClient defaultClient() {// 方便测试先注册一个测试客户端RegisteredClient oidcClient RegisteredClient.withId(UUID.randomUUID().toString()).clientId(client)// 123456.clientSecret($2a$10$gJUJo9Ad3wDIhBGVH.8/i.Ox82tSCR4.UkbiDWEDUVQnIzcTMPjKK)// 可以基于 basic 的方式和授权服务器进行认证.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)// 授权码.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)// 刷新token.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)// 客户端模式.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)// 密码模式.authorizationGrantType(AuthorizationGrantType.JWT_BEARER)// 重定向url.redirectUri(http://127.0.0.1:9000/callback).postLogoutRedirectUri(http://127.0.0.1:9000/)// 客户端申请的作用域也可以理解这个客户端申请访问用户的哪些信息比如获取用户信息获取用户照片等.scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).clientSettings(ClientSettings.builder()// 是否需要用户确认一下客户端需要获取用户的哪些权限// 比如客户端需要获取用户的 用户信息、用户照片 但是此处用户可以控制只给客户端授权获取 用户信息。.requireAuthorizationConsent(true).build()).tokenSettings(TokenSettings.builder()// accessToken 的有效期.accessTokenTimeToLive(Duration.ofHours(1))// refreshToken 的有效期.refreshTokenTimeToLive(Duration.ofDays(3))// 是否可重用刷新令牌.reuseRefreshTokens(true).build()).build();return oidcClient;}/*** 自定义授权service* return /*/Beanpublic OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) { // JdbcOAuth2AuthorizationService authorizationService new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository); // JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository); // ClassLoader classLoader JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper.class.getClassLoader(); // ObjectMapper objectMapper new ObjectMapper(); // objectMapper.registerModules(new CoreJackson2Module()); // objectMapper.registerModules(SecurityJackson2Modules.getModules(classLoader)); // objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module()); // rowMapper.setObjectMapper(objectMapper); // authorizationService.setAuthorizationRowMapper(rowMapper); // return authorizationService;return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);}/*** 自定义确认授权 service 配置**/Beanpublic OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,RegisteredClientRepository registeredClientRepository) {return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);}/*** 签名实例* 此处注意目前重启项目就会导致之前已存在的token失效需要改为固定私钥和公钥生成到项目目录下* return /*/Beanpublic JWKSourceSecurityContext jwkSource(){var keyPair generateRsaKeyPair();// 公钥RSAPublicKey publicKey (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey (RSAPrivateKey) keyPair.getPrivate();RSAKey rsaKey new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();var jwkSet new JWKSet(rsaKey);return new ImmutableJWKSet(jwkSet);}// 解析JWKSource访问令牌构建 JwtDecoder 实例Beanpublic JwtDecoder jwtDecoder(JWKSourceSecurityContext jwkSource){return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}// 启动时生成的 with 密钥的实例用于创建上述内容。java.security.KeyPairJWKSourceprivate static KeyPair generateRsaKeyPair(){KeyPair keyPair ;try {KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(RSA);keyPairGenerator.initialize(2048);keyPair keyPairGenerator.generateKeyPair();}catch (Exception e) {throw new IllegalStateException(e);}return keyPair;}/*** 自定义jwt信息全局自定义jwt实现例外* return /*/Beanpublic OAuth2TokenCustomizerJwtEncodingContext jwtCustomizer() {return context - {context.getJwsHeader().header(client-id, context.getRegisteredClient().getClientId());context.getClaims().claim(test,哈哈哈).build();log.info(jwtCustomizer - getJwsHeader:{},context.getJwsHeader());log.info(jwtCustomizer - claim:{}, context.getClaims());// Customize claims};}/*** 自定义token属性 预留* return /*/Beanpublic OAuth2TokenCustomizerOAuth2TokenClaimsContext accessTokenCustomizer() {return context - {OAuth2TokenClaimsSet.Builder claims context.getClaims();claims.claim(test200,哈哈哈哈哈).build();log.info(accessTokenCustomizer - claims:{},claims);// Customize claims};}// Jwt编码上下文 拓展token // Bean // public OAuth2TokenCustomizerJwtEncodingContext jwtCustomizer() { // return context - { // JwsHeader.Builder headers context.getJwsHeader(); // JwtClaimsSet.Builder claims context.getClaims(); // headers.header(client-id, context.getRegisteredClient().getClientId()); // log.info(jwtCustomizer headers:{},headers); // if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) { // // Customize headers/claims for access_token // // } else if (context.getTokenType().getValue().equals(OidcParameterNames.ID_TOKEN)) { // // Customize headers/claims for id_token // } // }; // }// 自定义 授权服务器的实例设置用于配置spring授权服务器Beanpublic AuthorizationServerSettings authorizationServerSettings() {// 总之server服务例如个性化认证及授权相关的路径return AuthorizationServerSettings.builder().build();}// 会话管理 // Bean // public SessionRegistry sessionRegistry() { // return new SessionRegistryImpl(); // }// Bean // public HttpSessionEventPublisher httpSessionEventPublisher() { // return new HttpSessionEventPublisher(); // }} MybatisPlusConfig Configuration public class MybatisPlusConfig {/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor false 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}controller包 ClientController 注册客户端 RequestMapping(/oauth2/client) RestController RequiredArgsConstructor public class ClientController {private final RegisteredClientRepository registeredClientRepository;private final PasswordEncoder passwordEncoder;/*** 注册客户端*/PostMappingpublic ResponseEntityBoolean registeredClientRepository(RequestBody RegisteredOauth2Client registeredClient) {// formatter:offRegisteredClient entity RegisteredClient.withId(UUID.randomUUID().toString())// ID.clientId(registeredClient.getClientId())// 秘钥.clientSecret(passwordEncoder.encode(registeredClient.getClientSecret()))// POST 请求方法.clientAuthenticationMethods(clientAuthenticationMethods -clientAuthenticationMethods.addAll(registeredClient.getClientAuthenticationMethods()))// CLIENT_CREDENTIALS.authorizationGrantTypes(authorizationGrantTypes -authorizationGrantTypes.addAll(registeredClient.getAuthorizationGrantTypes()))// 范围.scopes(strings - {// 超级strings.addAll(registeredClient.getScopes());}).tokenSettings(registeredClient.getTokenSettings())// 客户端配置.clientSettings(registeredClient.getClientSettings()).build();// Save registered client in dbregisteredClientRepository.save(entity);return ResponseEntity.ok(true);}}InfoController 测试 当前认证上下文信息 RestController RequestMapping(/info) public class InfoController {GetMapping(/token)public Object token(){return SecurityContextHolder.getContext().getAuthentication().getPrincipal();}}domain BaseResponseDto Data AllArgsConstructor NoArgsConstructor Builder public class BaseResponseDto {private String code;private String message;} LoginRequest Data public class LoginRequest {private String username;private String password;}UserDto Data Accessors(chain true) public class UserDto {private String id;private String hosId;private String token;} RegisteredOauth2Client 重要 这个类可以着重看一下 Data NoArgsConstructor public class RegisteredOauth2Client implements Serializable {/*** 客户端ID*/private String clientId;/*** 客户端秘钥*/private String clientSecret;/*** 客户端名称*/private String clientName;/*** 权限范围*/private SetString scopes;private Instant clientIdIssuedAt;private Instant clientSecretExpiresAt;private SetClientAuthenticationMethod clientAuthenticationMethods;private SetAuthorizationGrantType authorizationGrantTypes;private SetString redirectUris;private ClientSettings clientSettings ClientSettings.builder()// 是否需要用户确认一下客户端需要获取用户的哪些权限// 比如客户端需要获取用户的 用户信息、用户照片 但是此处用户可以控制只给客户端授权获取 用户信息。.requireAuthorizationConsent(true).build();private TokenSettings tokenSettings TokenSettings.builder()// accessToken 的有效期.accessTokenTimeToLive(Duration.ofHours(1))// refreshToken 的有效期.refreshTokenTimeToLive(Duration.ofDays(3))// 是否可重用刷新令牌.reuseRefreshTokens(true).build(); }UserEntity Data TableName(user) public class UserEntity {TableId(id_)private Long id;TableField(username)private String username;TableField(password)private String password;}mapper UserMapper public interface UserMapper extends BaseMapperUserEntity {} service IUserService public interface IUserService extends IServiceUserEntity { } UserServiceImpl Service RequiredArgsConstructor public class UserServiceImpl extends ServiceImplUserMapper, UserEntity implements IUserService {} utils HelperUtils public class HelperUtils {public static final ObjectWriter JSON_WRITER new ObjectMapper().writer().withDefaultPrettyPrinter();}JwtUtils public final class JwtUtils {private JwtUtils() {}public static JwsHeader.Builder headers() {return JwsHeader.with(SignatureAlgorithm.RS256);}public static JwtClaimsSet.Builder accessTokenClaims(RegisteredClient registeredClient,String issuer, String subject,SetString authorizedScopes) {Instant issuedAt Instant.now();Instant expiresAt issuedAt.plus(registeredClient.getTokenSettings().getAccessTokenTimeToLive());/*** iss (issuer)签发人/发行人* sub (subject)主题* aud (audience)用户* exp (expiration time)过期时间* nbf (Not Before)生效时间在此之前是无效的* iat (Issued At)签发时间* jti (JWT ID)用于标识该 JWT*/// formatter:offJwtClaimsSet.Builder claimsBuilder JwtClaimsSet.builder();if (StringUtils.hasText(issuer)) {claimsBuilder.issuer(issuer);}claimsBuilder.subject(subject).audience(Collections.singletonList(registeredClient.getClientId())).issuedAt(issuedAt).expiresAt(expiresAt).notBefore(issuedAt);if (!CollectionUtils.isEmpty(authorizedScopes)) {claimsBuilder.claim(OAuth2ParameterNames.SCOPE, authorizedScopes);}// formatter:onreturn claimsBuilder;}public static JwtClaimsSet.Builder idTokenClaims(RegisteredClient registeredClient,String issuer, String subject, String nonce) {Instant issuedAt Instant.now();// TODO Allow configuration for ID Token time-to-liveInstant expiresAt issuedAt.plus(30, ChronoUnit.MINUTES);// formatter:offJwtClaimsSet.Builder claimsBuilder JwtClaimsSet.builder();if (StringUtils.hasText(issuer)) {claimsBuilder.issuer(issuer);}claimsBuilder.subject(subject).audience(Collections.singletonList(registeredClient.getClientId())).issuedAt(issuedAt).expiresAt(expiresAt).claim(IdTokenClaimNames.AZP, registeredClient.getClientId());if (StringUtils.hasText(nonce)) {claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce);}// TODO Add auth_time claim// formatter:onreturn claimsBuilder;}}OAuth2ConfigurerUtils /*** 复制security底层的工具类*/ public class OAuth2ConfigurerUtils {private OAuth2ConfigurerUtils() {}public static RegisteredClientRepository getRegisteredClientRepository(HttpSecurity httpSecurity) {RegisteredClientRepository registeredClientRepository (RegisteredClientRepository)httpSecurity.getSharedObject(RegisteredClientRepository.class);if (registeredClientRepository null) {registeredClientRepository (RegisteredClientRepository)getBean(httpSecurity, RegisteredClientRepository.class);httpSecurity.setSharedObject(RegisteredClientRepository.class, registeredClientRepository);}return registeredClientRepository;}public static OAuth2AuthorizationService getAuthorizationService(HttpSecurity httpSecurity) {OAuth2AuthorizationService authorizationService (OAuth2AuthorizationService)httpSecurity.getSharedObject(OAuth2AuthorizationService.class);if (authorizationService null) {authorizationService (OAuth2AuthorizationService)getOptionalBean(httpSecurity, OAuth2AuthorizationService.class);if (authorizationService null) {authorizationService new InMemoryOAuth2AuthorizationService();}httpSecurity.setSharedObject(OAuth2AuthorizationService.class, authorizationService);}return (OAuth2AuthorizationService)authorizationService;}public static OAuth2AuthorizationConsentService getAuthorizationConsentService(HttpSecurity httpSecurity) {OAuth2AuthorizationConsentService authorizationConsentService (OAuth2AuthorizationConsentService)httpSecurity.getSharedObject(OAuth2AuthorizationConsentService.class);if (authorizationConsentService null) {authorizationConsentService (OAuth2AuthorizationConsentService)getOptionalBean(httpSecurity, OAuth2AuthorizationConsentService.class);if (authorizationConsentService null) {authorizationConsentService new InMemoryOAuth2AuthorizationConsentService();}httpSecurity.setSharedObject(OAuth2AuthorizationConsentService.class, authorizationConsentService);}return (OAuth2AuthorizationConsentService)authorizationConsentService;}public static OAuth2TokenGenerator? extends OAuth2Token getTokenGenerator(HttpSecurity httpSecurity) {OAuth2TokenGenerator? extends OAuth2Token tokenGenerator (OAuth2TokenGenerator)httpSecurity.getSharedObject(OAuth2TokenGenerator.class);if (tokenGenerator null) {tokenGenerator (OAuth2TokenGenerator)getOptionalBean(httpSecurity, OAuth2TokenGenerator.class);if (tokenGenerator null) {JwtGenerator jwtGenerator getJwtGenerator(httpSecurity);OAuth2AccessTokenGenerator accessTokenGenerator new OAuth2AccessTokenGenerator();OAuth2TokenCustomizerOAuth2TokenClaimsContext accessTokenCustomizer getAccessTokenCustomizer(httpSecurity);if (accessTokenCustomizer ! null) {accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer);}OAuth2RefreshTokenGenerator refreshTokenGenerator new OAuth2RefreshTokenGenerator();if (jwtGenerator ! null) {tokenGenerator new DelegatingOAuth2TokenGenerator(new OAuth2TokenGenerator[]{jwtGenerator, accessTokenGenerator, refreshTokenGenerator});} else {tokenGenerator new DelegatingOAuth2TokenGenerator(new OAuth2TokenGenerator[]{accessTokenGenerator, refreshTokenGenerator});}}httpSecurity.setSharedObject(OAuth2TokenGenerator.class, tokenGenerator);}return (OAuth2TokenGenerator)tokenGenerator;}private static JwtGenerator getJwtGenerator(HttpSecurity httpSecurity) {JwtGenerator jwtGenerator (JwtGenerator)httpSecurity.getSharedObject(JwtGenerator.class);if (jwtGenerator null) {JwtEncoder jwtEncoder getJwtEncoder(httpSecurity);if (jwtEncoder ! null) {jwtGenerator new JwtGenerator(jwtEncoder);OAuth2TokenCustomizerJwtEncodingContext jwtCustomizer getJwtCustomizer(httpSecurity);if (jwtCustomizer ! null) {jwtGenerator.setJwtCustomizer(jwtCustomizer);}httpSecurity.setSharedObject(JwtGenerator.class, jwtGenerator);}}return jwtGenerator;}private static JwtEncoder getJwtEncoder(HttpSecurity httpSecurity) {JwtEncoder jwtEncoder (JwtEncoder)httpSecurity.getSharedObject(JwtEncoder.class);if (jwtEncoder null) {jwtEncoder (JwtEncoder)getOptionalBean(httpSecurity, JwtEncoder.class);if (jwtEncoder null) {JWKSourceSecurityContext jwkSource getJwkSource(httpSecurity);if (jwkSource ! null) {jwtEncoder new NimbusJwtEncoder(jwkSource);}}if (jwtEncoder ! null) {httpSecurity.setSharedObject(JwtEncoder.class, jwtEncoder);}}return (JwtEncoder)jwtEncoder;}public static JWKSourceSecurityContext getJwkSource(HttpSecurity httpSecurity) {JWKSourceSecurityContext jwkSource (JWKSource)httpSecurity.getSharedObject(JWKSource.class);if (jwkSource null) {ResolvableType type ResolvableType.forClassWithGenerics(JWKSource.class, new Class[]{SecurityContext.class});jwkSource (JWKSource)getOptionalBean(httpSecurity, type);if (jwkSource ! null) {httpSecurity.setSharedObject(JWKSource.class, jwkSource);}}return jwkSource;}private static OAuth2TokenCustomizerJwtEncodingContext getJwtCustomizer(HttpSecurity httpSecurity) {ResolvableType type ResolvableType.forClassWithGenerics(OAuth2TokenCustomizer.class, new Class[]{JwtEncodingContext.class});return (OAuth2TokenCustomizer)getOptionalBean(httpSecurity, type);}private static OAuth2TokenCustomizerOAuth2TokenClaimsContext getAccessTokenCustomizer(HttpSecurity httpSecurity) {ResolvableType type ResolvableType.forClassWithGenerics(OAuth2TokenCustomizer.class, new Class[]{OAuth2TokenClaimsContext.class});return (OAuth2TokenCustomizer)getOptionalBean(httpSecurity, type);}public static AuthorizationServerSettings getAuthorizationServerSettings(HttpSecurity httpSecurity) {AuthorizationServerSettings authorizationServerSettings (AuthorizationServerSettings)httpSecurity.getSharedObject(AuthorizationServerSettings.class);if (authorizationServerSettings null) {authorizationServerSettings (AuthorizationServerSettings)getBean(httpSecurity, AuthorizationServerSettings.class);httpSecurity.setSharedObject(AuthorizationServerSettings.class, authorizationServerSettings);}return authorizationServerSettings;}public static T T getBean(HttpSecurity httpSecurity, ClassT type) {return ((ApplicationContext)httpSecurity.getSharedObject(ApplicationContext.class)).getBean(type);}public static T T getBean(HttpSecurity httpSecurity, ResolvableType type) {ApplicationContext context (ApplicationContext)httpSecurity.getSharedObject(ApplicationContext.class);String[] names context.getBeanNamesForType(type);if (names.length 1) {return (T) context.getBean(names[0]);} else if (names.length 1) {throw new NoUniqueBeanDefinitionException(type, names);} else {throw new NoSuchBeanDefinitionException(type);}}public static T T getOptionalBean(HttpSecurity httpSecurity, ClassT type) {MapString, T beansMap BeanFactoryUtils.beansOfTypeIncludingAncestors((ListableBeanFactory)httpSecurity.getSharedObject(ApplicationContext.class), type);if (beansMap.size() 1) {int var10003 beansMap.size();String var10004 type.getName();throw new NoUniqueBeanDefinitionException(type, var10003, Expected single matching bean of type var10004 but found beansMap.size() : StringUtils.collectionToCommaDelimitedString(beansMap.keySet()));} else {return !beansMap.isEmpty() ? beansMap.values().iterator().next() : null;}}public static T T getOptionalBean(HttpSecurity httpSecurity, ResolvableType type) {ApplicationContext context (ApplicationContext)httpSecurity.getSharedObject(ApplicationContext.class);String[] names context.getBeanNamesForType(type);if (names.length 1) {throw new NoUniqueBeanDefinitionException(type, names);} else {return names.length 1 ? (T) context.getBean(names[0]) : null;}} } 效果截图 注册客户端 {clientId:123456, clientSecret:8b30c1482ff973cfc92e51e1ec636966, clientName:test, scopes:[ super ], clientAuthenticationMethods:[client_secret_post], authorizationGrantTypes: [refresh_token, client_credentials, sms_app,wechat_miniapp] }客户端授权 grant_type:wechat_miniapp scope:super client_id:123456 client_secret:8b30c1482ff973cfc92e51e1ec636966 appId:123456789不带access_token访问资源 带access_token访问资源 数据库截图 客户端 授权
http://www.zqtcl.cn/news/397712/

相关文章:

  • 网站百度关键词排名软件xampp里wordpress安装教程
  • 杭州网站设计建立企业网站专业做电脑系统下载网站好
  • 哈尔滨建设网站成本网站建设无广告
  • 发布网站搭建教程云排名网站
  • 无锡大型网站建设房地产景区网站建设方案
  • 自学网站建设工资公众号怎么开通直播功能
  • 网站建设上市公司wordpress park主题
  • 百度网站建设一年多少钱奇艺广州网站建设 熊掌号
  • 建设网站怎么收费标准网站和自媒体都可以做
  • 网站自己怎么做无锡常规网络营销是什么
  • 活泼风格的网站crm免费客户管理系统
  • 网站系统发生错误百度seo灰色词排名代发
  • 免费做名片儿的网站wordpress grace6
  • 有关网站开发的创意四川工程造价信息网官网
  • 网站目录结构北京注册公司地址可以是住宅吗
  • 龙信建设集团网站傻瓜式建站软件下载
  • 在360做网站和百度做网站的区别什么是网站地址
  • 营销型的物流网站模板下载长江设计公司
  • 网站程序制作购买网站域名
  • 网站建设中html下载如何用社交网站开发客户
  • 开设购物网站的方案政务公开和网站建设情况
  • 一台云服务器做多个网站营销型网站的建设重点是什么
  • 泉港网站建设推广服务公司电子商务好就业吗
  • 自己做网站开发如何找客户wordpress 显示 子分类
  • 腾讯邮箱网页版登录宿迁seo公司
  • 网站建设找盖亚科技WordPress 百度 主动
  • 中国最受欢迎的网站杭州做电商网站
  • 百度招聘 网站开发全网营销实战培训
  • 备案网站内容说明广州哪个区封了
  • 大足建网站的软件开发者模式怎么打开