官方文档
Spring Authorization Server
环境介绍
java:17
SpringBoot:3.2.0
SpringCloud:2023.0.0
引入maven配置
org.springframework.boot spring-boot-starter-securityorg.springframework.boot spring-boot-starter-oauth2-authorization-serverorg.springframework.boot spring-boot-starter-oauth2-client
AuthorizationServerConfig认证中心配置类
package com.auth.config; import com.jilianyun.exception.ServiceException; 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.http.MediaType; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; 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.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.jwt.JwtDecoder; 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.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.UUID; /** *认证中心配置类
* * @author By: chengxuyuanshitang * Ceate Time 2024-05-07 11:42 */ @Slf4j @EnableWebSecurity @Configuration(proxyBeanMethods = false) public class AuthorizationServerConfig { /** * Security过滤器链,用于协议端点 * * @param http HttpSecurity * @return SecurityFilterChain */ @Bean public SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity (http); http.getConfigurer (OAuth2AuthorizationServerConfigurer.class) //启用OpenID Connect 1.0 .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 (); } /** * 用于认证的Spring Security过滤器链。 * * @param http HttpSecurity * @return SecurityFilterChain */ @Bean public SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http) throws Exception { http.authorizeHttpRequests ((authorize) -> authorize .requestMatchers (new AntPathRequestMatcher ("/actuator/**"), new AntPathRequestMatcher ("/oauth2/**"), new AntPathRequestMatcher ("/**/*.json"), new AntPathRequestMatcher ("/**/*.css"), new AntPathRequestMatcher ("/**/*.html")).permitAll () .anyRequest ().authenticated () ) .formLogin (Customizer.withDefaults ()); return http.build (); } /** * 配置密码解析器,使用BCrypt的方式对密码进行加密和验证 * * @return BCryptPasswordEncoder */ @Bean public PasswordEncoder passwordEncoder () { return new BCryptPasswordEncoder (); } @Bean public UserDetailsService userDetailsService () { UserDetails userDetails = User.withUsername ("chengxuyuanshitang") .password (passwordEncoder ().encode ("chengxuyuanshitang")) .roles ("admin") .build (); return new InMemoryUserDetailsManager (userDetails); } /** * RegisteredClientRepository 的一个实例,用于管理客户端 * * @param jdbcTemplate jdbcTemplate * @param passwordEncoder passwordEncoder * @return RegisteredClientRepository */ @Bean public RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) { RegisteredClient registeredClient = RegisteredClient.withId (UUID.randomUUID ().toString ()) .clientId ("oauth2-client") .clientSecret (passwordEncoder.encode ("123456")) // 客户端认证基于请求头 .clientAuthenticationMethod (ClientAuthenticationMethod.CLIENT_SECRET_BASIC) // 配置授权的支持方式 .authorizationGrantType (AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType (AuthorizationGrantType.REFRESH_TOKEN) .authorizationGrantType (AuthorizationGrantType.CLIENT_CREDENTIALS) .redirectUri ("https://www.baidu.com") .scope ("user") .scope ("admin") // 客户端设置,设置用户需要确认授权 .clientSettings (ClientSettings.builder ().requireAuthorizationConsent (true).build ()) .build (); JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository (jdbcTemplate); RegisteredClient repositoryByClientId = registeredClientRepository.findByClientId (registeredClient.getClientId ()); if (repositoryByClientId == null) { registeredClientRepository.save (registeredClient); } return registeredClientRepository; } /** * 用于签署访问令牌 * * @return JWKSource */ @Bean public JWKSourcejwkSource () { KeyPair keyPair = generateRsaKey (); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic (); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate (); RSAKey rsaKey = new RSAKey.Builder (publicKey) .privateKey (privateKey) .keyID (UUID.randomUUID ().toString ()) .build (); JWKSet jwkSet = new JWKSet (rsaKey); return new ImmutableJWKSet<> (jwkSet); } /** * 创建RsaKey * * @return KeyPair */ private static KeyPair generateRsaKey () { KeyPair keyPair; try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance ("RSA"); keyPairGenerator.initialize (2048); keyPair = keyPairGenerator.generateKeyPair (); } catch (Exception e) { log.error ("generateRsaKey Exception", e); throw new ServiceException ("generateRsaKey Exception"); } return keyPair; } /** * 解码签名访问令牌 * * @param jwkSource jwkSource * @return JwtDecoder */ @Bean public JwtDecoder jwtDecoder (JWKSource jwkSource) { return OAuth2AuthorizationServerConfiguration.jwtDecoder (jwkSource); } @Bean public AuthorizationServerSettings authorizationServerSettings () { return AuthorizationServerSettings.builder ().build (); } }
详细介绍
SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http)
Spring Security的过滤器链,用于协议端点
SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http)
Security的过滤器链,用于Security的身份认证
PasswordEncoder passwordEncoder ()
配置密码解析器,使用BCrypt的方式对密码进行加密和验证
UserDetailsService userDetailsService ()
用于进行用户身份验证
RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder)
用于管理客户端
JWKSource jwkSource ()
用于签署访问令牌
KeyPair generateRsaKey ()
创建RsaKey
JwtDecoder jwtDecoder (JWKSource jwkSource)
解码签名访问令牌
AuthorizationServerSettings authorizationServerSettings ()
配置Spring Authorization Server的AuthorizationServerSettings实例
初始化自带的数据表
自带的表在spring-security-oauth2-authorization-server-1.2.0.jar 中 下面是对应的截图
对应的SQL
-- 已注册的客户端信息表 CREATE TABLE oauth2_registered_client ( id varchar(100) NOT NULL, client_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_settings varchar(2000) NOT 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) ); /* 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) );
application.yml中数据库配置
spring: profiles: active: dev datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.0.1:3306/auth?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true username: auth password: 12345
启动AuthServerApplication
启动完成后查看数据库的oauth2_registered_client表中有一条数据;
查看授权服务配置
地址:http://127.0.0.1:8801/.well-known/openid-configuration
访问/oauth2/authorize前往登录页面
地址:ip/端口/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com
实例:
http://127.0.0.1:8801/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com
浏览器跳转到:http://127.0.0.1:8801/login
输入上面配置的密码和账号。我这里都是:chengxuyuanshitang 点击提交。跳转
跳转到
网址栏的地址:https://www.baidu.com/?code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt
code的值就是=后面的
code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt
获取token
请求地址:http://127.0.0.1:8801/oauth2/token?grant_type=authorization_code&redirect_uri=https://www.baidu.com&code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt
用postman请求
添加header参数
header中的 Authorization参数:因为我们用的客户端认证方式 为 client_secret_basic ,这个需要传参,还有一些其他的认证方式,
client_secret_basic: 将 clientId 和 clientSecret 通过 : 号拼接,并使用 Base64 进行编码得到一串字符,再在前面加个 注意有个 Basic 前缀(Basic后有一个空格), 即得到上面参数中的 Basic 。
我的是:app-client:123456
Base64 进行编码:YXBwLWNsaWVudDoxMjM0NTY=
返回:
{ "access_token": "eyJraWQiOiI2ZTJmYTA5ZS0zMmYzLTQ0MmQtOTM4Zi0yMzJjNDViYTM1YmMiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJjaGVuZ3h1eXVhbnNoaXRhbmciLCJhdWQiOiJhcHAtY2xpZW50IiwibmJmIjoxNzE1MDcxOTczLCJzY29wZSI6WyJ1c2VyIl0sImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6ODgwMSIsImV4cCI6MTcxNTA3MjI3MywiaWF0IjoxNzE1MDcxOTczLCJqdGkiOiI0MWI4ZGZmZS03MTI2LTQ4NWYtODRmYy00Yjk4OGE0N2ZlMzUifQ.VxP2mLHt-eyXHZOI36yhVlwC2UQEdAtaRBKTWwJn1bFup0ZjGbZfgxENUb1c03yjcki2H-gCW4Jgef11BMNtjyWSnwMHVWLB9fcT3rRKDQWwoWqBYAcULS8oC5n8qTZwffDSrnjepMEbw4CblL3oH7T9nLProTXQP326RIE1RczsUYkteUCkyIvKTSs3ezOjIVR1GyCs_Cl1A_3OllmkGnSO2q-NKkwasrQjMuuPTY3nhDyDGiefYlfDEcmzz1Yk_FE42P7PEeyqmZwAj7vUnE4brQuNqipaMsS7INe_wTE1kJv-arfbnUo_zQdipHxIhsDgoLaPlSSecQ31QgwEHA", "refresh_token": "TqJyWbLWe5Yww6dOV89zDbO0C3YEBA__0TJU_GclmQTAH92SSQ2OvdMChIdln97u1WsA7G7n3BqzNZBjPRU7xmkRooa5ifsMBJ-d3C4kPmuPQI-Bmbq20pck-QEk0Dqt", "scope": "user", "token_type": "Bearer", "expires_in": 300 }
访问接口/userinfo
请求地址:http://127.0.0.1:8801/userinfo
添加header参数:Authorization: Bearer +空格+ ${access_token}
还没有评论,来说两句吧...