Spring cloud入门-OAuth 2.0(四)授权之基于JWT完成单点登录

摘要

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

单点登录简介

单点登录简称SSO,只的是当有多个系统需要登录时,用户只需要登录一个系统就无须登录其他的系统

创建oauth2-client

这里新建一个oauth2-client作为客服端,使用oauth2-jwt-server服务作授权服务,当我们在oauth2-jwt-server登录了,就可以直接调用oauth2-client的接口,反之,则跳转oauth2-jwt-server进行登录

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>
    </dependencies>
server:
  port: 9300
  servlet:
    session:
      cookie:
        # 防止cookie冲突,冲突会导致登录验证不通过
        name: OAUTH2-CLIENT-SESSIONID
spring:
  application:
    name: oauth-client
oauth2-service-url: http://localhost:9200
security:
  oauth2:
    client:
      # 申请的client 的id(对应jwt服务的client-id)
      client-id: admin
      # 申请的client 的秘钥(对应jwt服务的client-secret)
      client-secret: admin
      # 获取code的地址
      user-authorization-uri: ${oauth2-service-url}/oauth/authorize

      # 拿到code获取access-token的URL
      access-token-uri: ${oauth2-service-url}/oauth/token
    resource:
      jwt:
        key-uri: ${oauth2-service-url}/oauth/token_key

启动类需要加上@EnableOAuth2Sso表示开启SSO验证

@EnableOAuth2Sso
@SpringBootApplication
public class Oauth2ClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(Oauth2ClientApplication.class, args);
	}
}

添加用于验证的客户端接口

@RestController
@RequestMapping("/user")
public class UserController {

	@GetMapping("/getUser")
	Object getUser(Authentication authentication) {
		return authentication;
	}

}

修改jwt服务的授权服务器(AuthorizationServerConfig)

package com.zglx.jwt.config;

import com.zglx.jwt.service.UserService;
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.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;

/**
 * @Description: 授权服务器
 * @Author: Zlx
 * @Date: 2021/10/17 5:09 下午
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private UserService userService;

	@Autowired
	@Qualifier("redisTokenStore")
	private TokenStore tokenStore;

	@Qualifier("jwtTokenStore")
	@Autowired
	private TokenStore jwtTokenStore;

	@Autowired
	@Qualifier("jwtAccessTokenConverter")
	private JwtAccessTokenConverter jwtAccessTokenConverter;

	@Autowired
	private JwtTokenEnhancer jwtTokenEnhancer;


	/**
	 * 使用密码模式需要配置
	 *
	 * @param endpoints endpoints
	 * @throws Exception
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//		// 自定义JWT内容增强器
		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		List<TokenEnhancer> delegates = new ArrayList<>();
		// 配置jwt内容增强器
		delegates.add(jwtTokenEnhancer);
		delegates.add(jwtAccessTokenConverter);
		tokenEnhancerChain.setTokenEnhancers(delegates);
		endpoints.authenticationManager(authenticationManager)
				// 配置用户数据源,登录的时候会执行userService的loadUserByUsername方法
				// 登录地址
				// http://localhost:9401/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all&state=normal
				.userDetailsService(userService)
				// 设置存储方式,这里使用redis
//				.tokenStore(tokenStore);
				.tokenStore(jwtTokenStore)
				.tokenEnhancer(tokenEnhancerChain)
				// 设置自定义token构造器
				.accessTokenConverter(jwtAccessTokenConverter);
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory()
				// 配置client_id
				.withClient("admin")
				// 配置client_secret
				.secret(passwordEncoder.encode("admin"))
				// 配置访问token的有效期
				.accessTokenValiditySeconds(3600)
				// 配置刷新token的有效期
				.refreshTokenValiditySeconds(864000)
				// 自动授权配置(api调用需要打开此配置,不然一直都要手动确认授权,如果是)
				.autoApprove(true)
				// 配置redirect_uri,用于授权成功后的跳转
				.redirectUris("http://localhost:9300/login")
				// 配置申请的权限范围
				.scopes("all")
				// 配置grant_type,表示授权类型,
				.authorizedGrantTypes("authorization_code", "password", "refresh_token");
	}

	/**
	 * 单点登录时必须验证
	 *
	 * @param security security
	 * @throws Exception
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.tokenKeyAccess("isAuthenticated()");
	}
}

网页单点服务验证

访问客户端需要授权的接口http://localhost:9300/user/getUser会跳转到授权服务的登录界面;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

服务调用验证

在这里插入图片描述
autoApprove必须打开,不然服务调用无法通过授权

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
登录成功后,postMan会自动生成一个token放到Headers的Authorization中
在这里插入图片描述
最后请求成功

{
  "authorities": [
    {
      "authority": "admin"
    }
  ],
  "details": {
    "remoteAddress": "0:0:0:0:0:0:0:1",
    "sessionId": "581EE1EE460FB72C2FD165393A0BC9B7",
    "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ6Z2x4Iiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTYzNTg3MDAwMSwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiODA0MTllOTgtZjA3My00Mjc4LTg0ZWItMjU1YWVjZjAzZTYwIiwiY2xpZW50X2lkIjoiYWRtaW4iLCJlbmhhbmNlIjoiZW5oYW5jZSBpbmZvIn0.wPmxNkAhtVPZNuhigaQYXIBaQigP7JPqtwVu2mCrHN8",
    "tokenType": "bearer",
    "decodedDetails": null
  },
  "authenticated": true,
  "userAuthentication": {
    "authorities": [
      {
        "authority": "admin"
      }
    ],
    "details": null,
    "authenticated": true,
    "principal": "zglx",
    "credentials": "N/A",
    "name": "zglx"
  },
  "oauth2Request": {
    "clientId": "admin",
    "scope": [
      "all"
    ],
    "requestParameters": {
      "client_id": "admin"
    },
    "resourceIds": [
      
    ],
    "authorities": [
      
    ],
    "approved": true,
    "refresh": false,
    "redirectUri": null,
    "responseTypes": [
      
    ],
    "extensions": {
      
    },
    "grantType": null,
    "refreshTokenRequest": null
  },
  "clientOnly": false,
  "principal": "zglx",
  "credentials": "",
  "name": "zglx"
}```

# oauth2-client添加权限校验
需要给client添加一个配置,用来添加方法级角色权限校验

```java
package com.example.oauth2client.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @Description:
 * @Author: Zlx
 * @Date: 2021/10/24 10:28 下午
 */
@Configuration
@Order(101)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

}

新增角色权限验证接口


	@GetMapping("/testRole")
	@PreAuthorize("hasAuthority('admin')")
	Object testRole(Authentication authentication) {
		return "Has admin auth!";
	}

如果postMan生成的token不是admin角色用户的,将返回如下信息
在这里插入图片描述

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Cloud OAuth2 JWT是一种基于Spring Cloud的身份验证和授权解决方案。OAuth2是一种开放标准,用于授权第三方应用程序访问用户资源的安全协议。JWT(JSON Web Token)是一种用于安全传输声明的开放标准。 Spring Cloud OAuth2 JWT通过使用OAuth2和JWT的结合,提供了一种安全的身份验证和授权机制。它使用JWT作为令牌来在用户和资源服务器之间进行认证和授权JWT包含了加密的用户信息和访问权限,并以密钥进行签名来确保其真实性。 使用Spring Cloud OAuth2 JWT,我们可以实现以下功能: 1. 提供用户身份验证和授权:通过验证用户的凭证和生成JWT令牌来验证用户身份,并授权给他们访问受保护资源的权限。 2. 单点登录(SSO):用户只需登录一次,即可获得访问多个应用程序的令牌,并可以在不再需要登录的情况下访问这些应用程序。 3. 远程授权:通过OAuth2授权服务器,支持远程对受保护资源的访问授权,确保只有被授权的用户能够访问资源。 4. 令牌刷新:JWT令牌在一段时间后会过期,但可以使用刷新令牌来重新生成新的令牌,以延长访问权限。 总之,Spring Cloud OAuth2 JWT提供了一个安全、可靠的身份验证和授权解决方案,可以在分布式系统环境下实现用户身份验证和授权的功能。它结合了OAuth2和JWT标准,提供了一种方便、灵活的身份验证和授权机制,使得开发者能够更好地保护应用程序和用户的安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值