【OAuth2】Spring Security OAuth2 token权限隔离

背景

由于项目OAuth2采用了多种模式,授权码模式为第三方系统接入,密码模式用于用户登录,Client模式用于服务间调用,

所有不同的模式下的token需要用**@PreAuthorize("hasAuthority('client')")进行隔离,遇到问题一直验证不通过。**

通过调试发现资源服务从授权服务拿到的authrities字段一直为空,StackOverFlow说低版本(项目中才2.0.15)的OAuth2实现权限隔离需要 重写UserInfoTokenService,但是资源服务太多所以考虑重写授权服务的返回值,如何重写?在哪里重写?是下面要介绍的~

哪里重写

资源服务器向授权服务服务器获取资源时候,返回的user信息重写,加入authorities

@Slf4j
@RestController
public class UserController {
  @Autowired
  HttpServletRequest request;

  @GetMapping("/user")
  public Principal user(Principal principal) {
    log.info("获取user信息:{}", JSON.toJSON(principal));    
	return principal; 
  }
}

返回的具体用户信息:参考原文

如何重写

principalOAuth2Authentication实例,OAuth2Authentication主要包括OAuth2Request storedRequestAuthentication userAuthentication
重写目的是将storedRequest authorities复制到authoritie中,但问题是authoritie不让修改的,没办法只能重写这个OAuth2Authentication了。

为了改变authoritie重写:

@GetMapping("/user")
public Principal user(Principal principal) {
  log.info("获取user信息:{}", JSON.toJSON(principal));
  OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
  OAuth2Request storedRequest = oAuth2Authentication.getOAuth2Request();
  Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
  // 为了服务端进行token权限隔离 定制OAuth2Authentication
  CustomOAuth2Authentication customOAuth2Authentication = 
      new CustomOAuth2Authentication(storedRequest, userAuthentication, storedRequest.getAuthorities());
  customOAuth2Authentication.setDetails(oAuth2Authentication.getDetails());
  log.info("返回用户信息:{}", JSON.toJSON(customOAuth2Authentication));
  return customOAuth2Authentication;
}

CustomOAuth2Authentication

package com.brightcns.wuxi.citizencard.auth.domain;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Request;

import java.util.Collection;

/**
 * @author maxianming
 * @date 2018/10/29 13:53
 */
public class CustomOAuth2Authentication extends AbstractAuthenticationToken {

    private static final long serialVersionUID = -4809832298438307309L;

    private final OAuth2Request storedRequest;

    private final Authentication userAuthentication;

    /**
     * Construct an OAuth 2 authentication. Since some grant types don't require user authentication, the user
     * authentication may be null.
     * @param storedRequest      The authorization request (must not be null).
     * @param userAuthentication The user authentication (possibly null).
     */
    public CustomOAuth2Authentication(OAuth2Request storedRequest, Authentication userAuthentication, Collection<? extends GrantedAuthority> authorities) {
        /**
         * 为了服务端进行token权限隔离 {@link @PreAuthorize("hasAuthority('server')")},自定义OAuth2Authentication使得支持改变authorities
         */
        super(authorities != null ? authorities : userAuthentication == null ? storedRequest.getAuthorities() : userAuthentication.getAuthorities());
        this.storedRequest = storedRequest;
        this.userAuthentication = userAuthentication;
    }

    public Object getCredentials() {
        return "";
    }

    public Object getPrincipal() {
        return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication
                .getPrincipal();
    }

    /**
     * Convenience method to check if there is a user associated with this token, or just a client application.
     *
     * @return true if this token represents a client app not acting on behalf of a user
     */
    public boolean isClientOnly() {
        return userAuthentication == null;
    }

    /**
     * The authorization request containing details of the client application.
     *
     * @return The client authentication.
     */
    public OAuth2Request getOAuth2Request() {
        return storedRequest;
    }

    /**
     * The user authentication.
     *
     * @return The user authentication.
     */
    public Authentication getUserAuthentication() {
        return userAuthentication;
    }

    @Override
    public boolean isAuthenticated() {
        return this.storedRequest.isApproved()
                && (this.userAuthentication == null || this.userAuthentication.isAuthenticated());
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        if (this.userAuthentication != null && CredentialsContainer.class.isAssignableFrom(this.userAuthentication.getClass())) {
            CredentialsContainer.class.cast(this.userAuthentication).eraseCredentials();
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof CustomOAuth2Authentication)) {
            return false;
        }
        if (!super.equals(o)) {
            return false;
        }

        CustomOAuth2Authentication that = (CustomOAuth2Authentication) o;

        if (!storedRequest.equals(that.storedRequest)) {
            return false;
        }
        if (userAuthentication != null ? !userAuthentication.equals(that.userAuthentication)
                : that.userAuthentication != null) {
            return false;
        }

        if (getDetails() != null ? !getDetails().equals(that.getDetails()) : that.getDetails() != null) {
            // return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + storedRequest.hashCode();
        result = 31 * result + (userAuthentication != null ? userAuthentication.hashCode() : 0);
        return result;
    }

}

主要在OAuth2Authentication基础上修改了30-35行代码

本文转载自博客园作者**浮生半日**的Spring Security OAuth2 token权限隔离一文。

新版本配置凭证式权限

使用spring-cloud-starter-oauth2:Greenwich.SR1版本,且客户端使用JdbcTokenStore时,可以修改oauth_client_details表对应的client的authrities以达到给client配置权限的目的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security 中设置 OAuth2 token endpoint 需要进行以下步骤: 1. 首先,确保你已经添加了 Spring Security OAuth2 的依赖。可以在 `pom.xml` 文件中添加以下依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> ``` 2. 在 Spring Security 的配置类中,添加 `@EnableOAuth2Client` 注解以启用 OAuth2 客户端功能。例如: ```java @Configuration @EnableWebSecurity @EnableOAuth2Client public class SecurityConfig extends WebSecurityConfigurerAdapter { // 配置其他的安全设置 } ``` 3. 在 `application.properties`(或 `application.yml`)文件中,配置 OAuth2 的相关属性。例如: ```properties spring.security.oauth2.client.registration.google.client-id=YOUR_CLIENT_ID spring.security.oauth2.client.registration.google.client-secret=YOUR_CLIENT_SECRET spring.security.oauth2.client.registration.google.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth spring.security.oauth2.client.provider.google.token-uri=https://www.googleapis.com/oauth2/v4/token spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo spring.security.oauth2.client.provider.google.user-name-attribute=name ``` 注意:上述示例中的属性是以 Google OAuth2 作为示例,你需要将其替换为你使用的实际 OAuth2 提供商的属性。 4. 最后,你可以使用 `SecurityConfig` 类的 `configure(HttpSecurity http)` 方法来配置 Spring Security 的其他安全设置。例如: ```java @Configuration @EnableWebSecurity @EnableOAuth2Client public class SecurityConfig extends WebSecurityConfigurerAdapter { // 配置其他的安全设置 @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/oauth2/**", "/login/**").permitAll() .anyRequest().authenticated() .and() .oauth2Login() .loginPage("/login") .defaultSuccessUrl("/home") .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/") .permitAll(); } } ``` 以上示例中,`configure(HttpSecurity http)` 方法配置了登录页、登录成功后的默认跳转页面和注销功能。 这是一个简单的设置 OAuth2 token endpoint 的示例,你可以根据自己的需求进行更详细的配置和定制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值