当前位置: 首页 > 知识库问答 >
问题:

Spring OAuth2授权:拒绝访问

佴德曜
2023-03-14

我对spring security&oauth2相当陌生。作为学习的一部分,我试图设置一个OAuth2授权服务器,并保护RESTendpoint免受未经授权的访问。

/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

代码

资源服务器

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);
    }



}
security:
  oauth2:
    resource:
      user-info-uri: http://localhost:9090/user
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;
        }

    }
+-----------+--------------+----------------------------------------------------------------------+------------+--------------------------------------------------------------+----------------------------+--------------------+-----------------------+------------------------+------------------------+-------------+
| 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. 如果我们只使用权限(@preauthorize(“hasauthorize('...')”))进行授权,它可以正常工作
  3. 作用域在到达oauth2ExpressionUtils-->hasAnyScope()时在authiEntication.oauth2Request中丢失(空列表)。
  4. 作用域由授权服务器的/userendpoint提供

{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={ULL,username=product_user,authorities=[{id=4,authority=role_product_user}],accountnonexpired=true,accountnonlocked=true,credentialsnonexpired=true,credenabled=true},credentials=true,credentials=null,name=product_user},credentials=true,credentials=oauth2request={clientid=reader,scope=[read],=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个paramter是一组表示作用域的字符串,它作为null传递!

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

共有1个答案

麻超
2023-03-14

正如您已经注意到并在问题#5096中提到的,默认的UserInfotokenServices不支持作用域,因此#oauth2.hasscope功能。一个可能的解决方案是实现自定义ResourceServerTokenServices

我还想提请您注意这样一个事实:Spring Security OAuth项目是不推荐的,不建议使用。

 类似资料:
  • 我正在尝试向Google AdWords API发出任何请求,该请求将返回非错误。 我使用开发者令牌创建了生产MCC帐户,此外,我还从测试帐户在google开发者控制台中创建了测试MCC帐户和OAuth2应用程序。 另外,我已经测试了不同的帐户(生产MCC,测试MCC,启用adword的用户,没有adword的用户)为auth应用程序/用户从谁的请求已 适用于任何设置/不同的客户端。我正在获取访问

  • 问题内容: 我看过许多类似的问题,因此表明我已经检查了基础知识。当然,这并不意味着我没有错过任何显而易见的东西。:-) 我的问题是:为什么我拒绝具有特权的用户访问权限,而我却已经在其中输入密码并被授予访问权限?(为了完整起见,我尝试输入错误的密码只是为了确保MySQL客户端在程序启动时拒绝我访问。) 背景: 通过ssh登录到运行MySQL服务器的计算机的外壳,我以root用户身份登录: 太棒了 我

  • 新并行/分布式计算和有问题的客户端服务器程序,我试图写。应该发生的是,服务器从客户端接收一个整数,并将总和发送回所有通向它的数字(例如,用户输入5,服务器计算1 2 3 4 5,服务器发送回15)。我还在试图弄清楚,所以我在客户端对输入进行了硬编码。 这就是我在服务器端所拥有的: 在客户端: 我也在客户端实现了接口。 我在客户端遇到的错误是: 异常线程"main"java.security.Acc

  • 因此,如果我以角色的身份登录,我就可以很好地访问这个视图。 但是,让我们做一个小的改变,重写一个方法... 这会给我一个...我不明白为什么。 为什么?!! 希望能得到一些帮助来解决这个问题。

  • 从今天起,我们的Airflow服务无法访问BigQuery中的查询。所有作业都会失败,并显示以下消息: [2021-03-12 10:17:28079]{taskinstance.py:1150}错误-原因:403获取https://bigquery.googleapis.com/bigquery/v2/projects/waipu-app-prod/queries/e62030d7-36eb-4

  • 配置: 我正在使用JWT,所以我有一个过滤器来创建基于它的用户: 我的userDetailsService填充GrantedAuthorities: