创建一个SSO单点登陆的客户端工程
需要的依赖和之前的项目基本一致:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.zeal4j</groupId> <artifactId>sso-client</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sso-client</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version><!--<version>Greenwich.SR2</version>--> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
YML配置:
server:
port: 8081 # 防止和服务端的端口冲突
servlet:
session:
cookie:
name: 'SSO-CLIENT-SESSION-ID' # 防止COOKIE冲突
# 授权服务器地址:
oauth2-server-url: http://localhost:8080
# 授权服务器的相关配置
security:
oauth2:
resource:
jwt:
key-uri: ${oauth2-server-url}/oauth/token_key
client:
client-id: admin
client-secret: 112233
user-authorization-uri: ${oauth2-server-url}/oauth/authorize
access-token-uri: ${oauth2-server-url}/oauth/token
客户端启动类打上支持SSO单点登陆注解
然后写一个简单的信息获取接口
package cn.zeal4j.controller; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @author Administrator * @file IntelliJ IDEA Spring-Security-SSO-Client * @create 2020 09 30 0:38 */ @Controller @RequestMapping("user") public class UserController { /** * user/getCurrentUser * @param authentication * @return */ @RequestMapping("getCurrentUser") @ResponseBody public Object getCurrentUser(Authentication authentication) { return authentication.getPrincipal(); } }
回到服务端,设置跳转的地址是客户端IP位置:
package cn.zeal4j.configuration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import java.util.ArrayList; import java.util.List; /** * @author Administrator * @file Spring-Security + Oauth2 * @create 2020 09 29 11:48 * @description 授权服务器配置 */ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Autowired private AuthenticationManager authenticationManager; @Qualifier("customUserDetailsServiceImpl") @Autowired private UserDetailsService userDetailsService; @Qualifier("getTokenStore") @Autowired private TokenStore tokenStore; @Qualifier("getJwtAccessTokenConverter") @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Qualifier("getJwtTokenEnhancer") @Autowired private TokenEnhancer tokenEnhancer; // @Qualifier("getRedisTokenStore") // @Autowired // private TokenStore tokenStore; /** * 使用密码模式需要的配置方法 * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // - - - - - 配置JWT自定义申明增强 Starter - - - - - TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); List<TokenEnhancer> tokenEnhancerList = new ArrayList<>(); tokenEnhancerList.add(tokenEnhancer); tokenEnhancerList.add(jwtAccessTokenConverter); tokenEnhancerChain.setTokenEnhancers(tokenEnhancerList); // - - - - - 配置JWT自定义申明增强 End - - - - - endpoints. authenticationManager(authenticationManager). userDetailsService(userDetailsService). accessTokenConverter(jwtAccessTokenConverter). tokenEnhancer(tokenEnhancerChain); // tokenStore(tokenStore); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients. inMemory(). withClient("admin"). secret(passwordEncoder.encode("112233")). // accessTokenValiditySeconds(3600). // 令牌有效时间 一小时 // redirectUris("http://www.baidu.com"). // 授权成功的跳转 accessTokenValiditySeconds(3600). // 过期时间 refreshTokenValiditySeconds(864000). // 刷新令牌的过期时间 redirectUris("http://localhost:8081/login"). autoApprove(true). //自动授权 scopes("all"). // 所有范围 // authorizedGrantTypes("authorization_code"); // 授权类型:授权码模式 authorizedGrantTypes("password", "refresh_token", "authorization_code"); // 授权类型:密码模式 追加令牌刷新,和兼容授权码模式 } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 密钥获取之前的身份认证,单点登陆必须配置 security.tokenKeyAccess("isAuthenticated()"); } }
配置完成后先启动服务端,再启动客户端,注意不要同时启动,我出现了一个进程占用的情况
两个服务都无法开启,手动杀死8080端口的进程解决了
两边控制台显示运行成功之后,访问客户端的接口:
http://localhost:8081/user/getCurrentUser
结果会被重定向到服务端的登陆:
http://localhost:8080/login
输入用户信息登陆之后,会自动跳回到我们一开始希望访问的接口:
直接获取authentication对象能得到完整的信息
package cn.zeal4j.controller; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @author Administrator * @file IntelliJ IDEA Spring-Security-SSO-Client * @create 2020 09 30 0:38 */ @Controller @RequestMapping("user") public class UserController { /** * user/getCurrentUser * @param authentication * @return */ @RequestMapping("getCurrentUser") @ResponseBody public Object getCurrentUser(Authentication authentication) { // return authentication.getPrincipal(); return authentication; } }
JSON数据:
{ "authorities": [{ "authority": "admin" }], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": "C7FBF0520D8CA4DF4131B9E05965B6AA", "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MDE0MDI1NjIsImp3dC1rZXktYWFhIjoiand0LXZhbHVlLUFBQSIsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImFhMjJkNmY2LWMxYzMtNDg0ZS1iZjI5LTYzZTg1Y2ZlZGY4YSIsImp3dC1rZXktYmJiIjoiand0LXZhbHVlLUJCQiIsImNsaWVudF9pZCI6ImFkbWluIiwiand0LWtleS1jY2MiOiJqd3QtdmFsdWUtQ0NDIn0.LG-D88n-hNoVOG1hrlpwEs-64jA-T2TPdlRi0cram-w", "tokenType": "bearer", "decodedDetails": null }, "authenticated": true, "userAuthentication": { "authorities": [{ "authority": "admin" }], "details": null, "authenticated": true, "principal": "admin", "credentials": "N/A", "name": "admin" }, "principal": "admin", "credentials": "", "clientOnly": false, "oauth2Request": { "clientId": "admin", "scope": ["all"], "requestParameters": { "client_id": "admin" }, "resourceIds": [], "authorities": [], "approved": true, "refresh": false, "redirectUri": null, "responseTypes": [], "extensions": {}, "grantType": null, "refreshTokenRequest": null }, "name": "admin" }
代码笔记已上传到Gitee仓库中,需要的自取:
https://gitee.com/daizhizhou/spring-security-tutorial