【OAuth2】Spring Security OAuth2 token权限隔离

本文介绍了在OAuth2环境下,为了解决不同模式下的token隔离问题,如何重写授权服务的返回值以添加authorities。通过创建自定义的CustomOAuth2Authentication类,实现了对原始OAuth2Authentication的扩展,允许修改authorities。此外,还提到了在新版本中,通过修改oauth_client_details表的authorities字段来配置客户端权限的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

由于项目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配置权限的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值