Spring Cloud Security:Oauth2实现单点登陆

SpringBoot实战电商项目mall(20k+star)地址: https://github.com/macrozheng/mall

摘要

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

单点登陆简介

单点登陆(Single Sign On)指的是当有多个系统须要登陆时,用户只需登陆一个系统,就能够访问其余须要登陆的系统而无需登陆。git

建立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/login,并添加获取秘钥时的身份认证。github

/**
 * 认证服务器配置
 * 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()"); // 获取密钥须要身份认证,使用单点登陆时必须配置
    }
}

网页单点登陆演示

  • 进行登陆操做后跳转到受权页面;

  • 受权后会跳转到原来须要权限的接口地址,展现登陆用户信息;

  • 若是须要跳过受权操做进行自动受权能够添加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认证方式获取访问令牌:

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

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

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

  • 最后请求接口能够获取到以下信息:
{
    "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权限的账号,好比andy:123456获取令牌后访问该接口,会发现没有权限访问。

使用到的模块

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

项目源码地址

https://github.com/macrozheng/springcloud-learningweb

公众号

mall项目全套学习教程连载中,关注公众号第一时间获取。spring

公众号图片

相关文章
相关标签/搜索