【Spring-Security】Re14 Oauth2协议P4 整合SSO单点登陆

创建一个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
原文地址:https://www.cnblogs.com/mindzone/p/13752642.html