2023-02-21  阅读(1)
原文作者:macrozheng 原文地址:https://www.macrozheng.com/cloud/cloud_catalog.html

# Spring Cloud Security:Oauth2实现单点登录

Spring Cloud Security 为构建安全的SpringBoot应用提供了一系列解决方案,结合Oauth2可以实现单点登录功能,本文将对其单点登录用法进行详细介绍。

# 单点登录简介

单点登录(Single Sign On)指的是当有多个系统需要登录时,用户只需登录一个系统,就可以访问其他需要登录的系统而无需登录。

# 创建oauth2-client模块

这里我们创建一个oauth2-client服务作为需要登录的客户端服务,使用上一节中的oauth2-jwt-server服务作为认证服务,当我们在oauth2-jwt-server服务上登录以后,就可以直接访问oauth2-client需要登录的接口,来演示下单点登录功能。

  • 在pom.xml中添加相关依赖:
    <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>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
  • 在application.yml中进行配置:
    server:
      port: 9501
      servlet:
        session:
          cookie:
            name: OAUTH2-CLIENT-SESSIONID #防止Cookie冲突,冲突会导致登录验证不通过
    oauth2-server-url: http://localhost:9401
    spring:
      application:
        name: oauth2-client
    security:
      oauth2: #与oauth2-server对应的配置
        client:
          client-id: admin
          client-secret: admin123456
          user-authorization-uri: ${oauth2-server-url}/oauth/authorize
          access-token-uri: ${oauth2-server-url}/oauth/token
        resource:
          jwt:
            key-uri: ${oauth2-server-url}/oauth/token_key
  • 在启动类上添加@EnableOAuth2Sso注解来启用单点登录功能:
    @EnableOAuth2Sso
    @SpringBootApplication
    public class Oauth2ClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(Oauth2ClientApplication.class, args);
        }
    
    }
  • 添加接口用于获取当前登录用户信息:
    /**
     * Created by macro on 2019/9/30.
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {
        
        @GetMapping("/getCurrentUser")
        public Object getCurrentUser(Authentication authentication) {
            return authentication;
        }
    
    }

# 修改认证服务器配置

修改oauth2-jwt-server模块中的AuthorizationServerConfig类,将绑定的跳转路径为http://localhost:9501/loginopen in new window,并添加获取秘钥时的身份认证。

    /**
     * 认证服务器配置
     * Created by macro on 2019/9/30.
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        //以上省略一堆代码...
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("admin")
                    .secret(passwordEncoder.encode("admin123456"))
                    .accessTokenValiditySeconds(3600)
                    .refreshTokenValiditySeconds(864000)
    //                .redirectUris("http://www.baidu.com")
                    .redirectUris("http://localhost:9501/login") //单点登录时配置
                    .scopes("all")
                    .authorizedGrantTypes("authorization_code","password","refresh_token");
        }
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) {
            security.tokenKeyAccess("isAuthenticated()"); // 获取密钥需要身份认证,使用单点登录时必须配置
        }
    }

# 网页单点登录演示

202302212304335141.png

  • 进行登录操作后跳转到授权页面;

202302212304342182.png

  • 授权后会跳转到原来需要权限的接口地址,展示登录用户信息;

202302212304353583.png

  • 如果需要跳过授权操作进行自动授权可以添加autoApprove(true)配置:
    /**
     * 认证服务器配置
     * Created by macro on 2019/9/30.
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        //以上省略一堆代码...
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("admin")
                    .secret(passwordEncoder.encode("admin123456"))
                    .accessTokenValiditySeconds(3600)
                    .refreshTokenValiditySeconds(864000)
    //                .redirectUris("http://www.baidu.com")
                    .redirectUris("http://localhost:9501/login") //单点登录时配置
                    .autoApprove(true) //自动授权配置
                    .scopes("all")
                    .authorizedGrantTypes("authorization_code","password","refresh_token");
        }
    }

# 调用接口单点登录演示

这里我们使用Postman来演示下如何使用正确的方式调用需要登录的客户端接口。

  • 访问客户端需要登录的接口:http://localhost:9501/user/getCurrentUser
  • 使用Oauth2认证方式获取访问令牌:

202302212304360754.png

  • 输入获取访问令牌的相关信息,点击请求令牌:

202302212304368025.png

  • 此时会跳转到认证服务器进行登录操作:

202302212304374106.png

  • 登录成功后使用获取到的令牌:

202302212304380447.png

  • 最后请求接口可以获取到如下信息:
    {
        "authorities": [
            {
                "authority": "admin"
            }
        ],
        "details": {
            "remoteAddress": "0:0:0:0:0:0:0:1",
            "sessionId": "63BB793E35383B2FFC608333B3BF4988",
            "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtYWNybyIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE1NzI2OTAxNzUsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjIwN2U5MTQzLTVjNTUtNDhkMS1iZmU3LTgwMzUyZTQ3Y2QyZCIsImNsaWVudF9pZCI6ImFkbWluIiwiZW5oYW5jZSI6ImVuaGFuY2UgaW5mbyJ9.xf3cBu9yCm0sME0j3UcP53FwF4tJVJC5aJbEj_Y2XcU",
            "tokenType": "bearer",
            "decodedDetails": null
        },
        "authenticated": true,
        "userAuthentication": {
            "authorities": [
                {
                    "authority": "admin"
                }
            ],
            "details": null,
            "authenticated": true,
            "principal": "macro",
            "credentials": "N/A",
            "name": "macro"
        },
        "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
        },
        "principal": "macro",
        "credentials": "",
        "name": "macro"
    }

# oauth2-client添加权限校验

  • 添加配置开启基于方法的权限校验:
    /**
     * 在接口上配置权限时使用
     * Created by macro on 2019/10/11.
     */
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Order(101)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    }
  • 在UserController中添加需要admin权限的接口:
    /**
     * Created by macro on 2019/9/30.
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @PreAuthorize("hasAuthority('admin')")
        @GetMapping("/auth/admin")
        public Object adminAuth() {
            return "Has admin auth!";
        }
    
    }
  • 访问需要admin权限的接口:http://localhost:9501/user/auth/admin

202302212304388668.png

  • 使用没有admin权限的帐号,比如andy:123456获取令牌后访问该接口,会发现没有权限访问。

202302212304395779.png

# 使用到的模块

    springcloud-learning
    ├── oauth2-jwt-server -- 使用jwt的oauth2认证测试服务
    └── oauth2-client -- 单点登录的oauth2客户端服务

# 项目源码地址

https://github.com/macrozheng/springcloud-learningopen in new window


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文