gpt4 book ai didi

java - Spring OAuth2授权: Access Denied

转载 作者:行者123 更新时间:2023-11-30 01:41:53 24 4
gpt4 key购买 nike

我对 Spring Security 和 OAuth2 还很陌生。作为学习的一部分,我尝试设置一个OAuth2 授权服务器保护 REST 端点免遭未经授权的访问。

我的资源服务器包含几个端点,具有以下授权。

/products : only user with Authority='ROLE_PRODUCT_USER' and scope='read' can access this endpoint
/addProduct : only user with Authority='ROLE_PRODUCT_ADMIN' and scope='write' can access this endpoint

ISSUE: Access denied while trying to access the end points using postman and grant_type="password"

代码

Resource Server

ProductController.java

@RestController
public class ProductController {

@Autowired
private ProductService productService;

@PreAuthorize("#oauth2.hasScope('read') and hasAuthority('ROLE_PRODUCT_USER')")
@GetMapping("/products")
public ResponseEntity<List<Product>> getAllProducts() {
return new ResponseEntity<List<Product>>(productService.getAllProducts(), HttpStatus.OK);
}

@PreAuthorize("#oauth2.hasScope('write') and hasAuthority('ROLE_PRODUCT_ADMIN')")
@PostMapping("/addproduct")
public ResponseEntity<Product> addProduct(@RequestBody Product product) {
return new ResponseEntity<Product>(productService.addProduct(product), HttpStatus.OK);
}



}

资源服务器中的 OAuth 配置

security:
oauth2:
resource:
user-info-uri: http://localhost:9090/user

Authorization Server

实现 user-info-uri 的主类

import java.security.Principal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
@RestController
public class OAuthAuthorizationServerApplication {

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

@GetMapping("/user")
public Principal user(Principal user) {
System.out.println(user);
return user;
}

}

Database oauth_client_details

mysql> select * from oauth_client_details where client_id in ('reader','writer');

+-----------+--------------+----------------------------------------------------------------------+------------+--------------------------------------------------------------+----------------------------+--------------------+-----------------------+------------------------+------------------------+-------------+
| client_id | resource_ids | client_secret | scope | authorized_grant_types | web_server_redirect_uri | authorities | access_token_validity | refresh_token_validity | additional_information | autoapprove |
+-----------+--------------+----------------------------------------------------------------------+------------+--------------------------------------------------------------+----------------------------+--------------------+-----------------------+------------------------+------------------------+-------------+
| reader | product_api | {bcrypt}removed | read | client_credentials,password,refersh_token,authorization_code | http://localhost:8080/home | ROLE_PRODUCT_USER | 10800 | 2592000 | NULL | NULL |
| writer | product_api | {bcrypt}removed | read,write | client_credentials,password,refersh_token,authorization_code | http://localhost:8080/home | ROLE_PRODUCT_ADMIN | 10800 | 2592000 | NULL | NULL |
+-----------+--------------+----------------------------------------------------------------------+------------+--------------------------------------------------------------+----------------------------+--------------------+-----------------------+------------------------+------------------------+-------------+

分析

  1. API无需授权即可正常工作
  2. 如果我们仅向 Authority 授权 (@PreAuthorize("hasAuthority('...')")),效果很好
  3. 当 Authentication.OAuth2Request 到达时,范围缺失(空列表), OAuth2ExpressionUtils --> hasAnyScope()。
  4. 范围由授权服务器的/user 端点提供

{authorities=[{id=4, authority=ROLE_PRODUCT_USER}], details={remoteAddress=127.0.0.1, sessionId=null, tokenValue=2f54e499-e47a-45fe-a6f6-e4c9593f9841, tokenType=Bearer, decodedDetails=null}, authenticated=true, userAuthentication={authorities=[{id=4, authority=ROLE_PRODUCT_USER}], details={clinet_id=reader, grant_type=password, username=product_user}, authenticated=true, principal={password=null, username=product_user, authorities=[{id=4, authority=ROLE_PRODUCT_USER}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}, credentials=null, name=product_user}, credentials=, oauth2Request={clientId=reader, scope=[read], requestParameters={clinet_id=reader, grant_type=password, username=product_user}, resourceIds=[product_api], authorities=[{authority=ROLE_PRODUCT_USER}], approved=true, refresh=false, redirectUri=null, responseTypes=[], extensions={}, grantType=password, refreshTokenRequest=null}, principal={password=null, username=product_user, authorities=[{id=4, authority=ROLE_PRODUCT_USER}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}, clientOnly=false, name=product_user}

  • 但是在 UserInfoTokenServices.extractAuthentication() 中创建 OAuth2Request 时它不会保留

    private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
    Object principal = getPrincipal(map);
    List<GrantedAuthority> authorities = this.authoritiesExtractor
    .extractAuthorities(map);
    OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
    null, null, null, null);
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
    principal, "N/A", authorities);
    token.setDetails(map);
    return new OAuth2Authentication(request, token); }
  • 这里的第5个参数是一组表示范围的字符串,以null传递!

    OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null, null, null, null, null);

    我这里缺少任何配置吗?

    最佳答案

    正如您已经注意到的那样,并且如 Issue #5096 中提到的那样,默认的 UserInfoTokenServices 不支持范围,因此不支持#oauth2.hasScope 功能。一种可能的解决方案是实现自定义 ResourceServerTokenServices

    我还想提请您注意 Spring Security OAuth项目已弃用,不建议使用。

    关于java - Spring OAuth2授权: Access Denied,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59656770/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com