ソースを参照

增加资源管理控制resourceMgt和api权限管理控制openapiRight

shimingxy 2 週間 前
コミット
3a64a5d8b2
24 ファイル変更379 行追加139 行削除
  1. 18 6
      maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/entity/Message.java
  2. 20 7
      maxkey-entity/src/main/java/org/dromara/maxkey/entity/apps/Apps.java
  3. 49 48
      maxkey-entity/src/main/java/org/dromara/maxkey/entity/apps/AppsOAuth20Details.java
  4. 9 0
      maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/AppsMapper.xml
  5. 6 12
      maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java
  6. 6 12
      maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestUserInfoController.java
  7. 16 9
      maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestUserPasswordController.java
  8. 1 1
      maxkey-web-frontend/maxkey-web-app/package.json
  9. 1 1
      maxkey-web-frontend/maxkey-web-mgt-app/package.json
  10. 1 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/entity/Apps.ts
  11. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-basic-details-editer/app-basic-details-editer.component.html
  12. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-cas-details-editer/app-cas-details-editer.component.html
  13. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-extend-api-details-editer/app-extend-api-details-editer.component.html
  14. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-form-based-details-editer/app-form-based-details-editer.component.html
  15. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-jwt-details-editer/app-jwt-details-editer.component.html
  16. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-oauth20-details-editer/app-oauth20-details-editer.component.html
  17. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-saml20-details-editer/app-saml20-details-editer.component.html
  18. 25 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-token-based-details-editer/app-token-based-details-editer.component.html
  19. 27 25
      maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.ts
  20. 2 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json
  21. 2 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json
  22. 2 0
      maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json
  23. 1 1
      maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/apps/controller/OAuth20DetailsController.java
  24. 18 17
      maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/web/interceptor/RestApiPermissionAdapter.java

+ 18 - 6
maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/entity/Message.java

@@ -21,12 +21,12 @@ import org.springframework.http.ResponseEntity;
 
 public class Message<T> {
     
-    public static final  int SUCCESS    = 0;    //成功
-    public static final  int ERROR        = 1;    //错误
-    public static final  int FAIL        = 2;    //失败
-    public static final  int INFO        = 101;    //信息
-    public static final  int PROMPT        = 102;    //提示
-    public static final  int WARNING    = 103;    //警告
+    public static final  int SUCCESS    	= 0;    //成功
+    public static final  int ERROR        	= 1;    //错误
+    public static final  int FAIL        	= 2;    //失败
+    public static final  int INFO        	= 101;    //信息
+    public static final  int PROMPT        	= 102;    //提示
+    public static final  int WARNING    	= 103;    //警告
     
     int code;
     
@@ -90,6 +90,18 @@ public class Message<T> {
         this.data = data;
     }
     
+    public static <T> Message<T> ok() {
+        return new Message<>(SUCCESS);
+    }
+    
+    public static <T> Message<T> ok(T data) {
+        return new Message<>(SUCCESS , data);
+    }
+    
+    public static <T> Message<T> failed(String msg) {
+        return new Message<>(FAIL , msg);
+    }
+    
     public ResponseEntity<?>  buildResponse() {
         return ResponseEntity.ok(this);
     }

+ 20 - 7
maxkey-entity/src/main/java/org/dromara/maxkey/entity/apps/Apps.java

@@ -165,6 +165,10 @@ public class Apps extends JpaEntity implements Serializable {
     @Column
     protected String description;
     @Column
+    String resourceMgt;
+    @Column
+    String openapiRight;
+    @Column
     private String instId;
     
     private String instName;
@@ -176,8 +180,6 @@ public class Apps extends JpaEntity implements Serializable {
         isSignature = ConstsBoolean.FALSE;
     }
 
-  
-
     public String getId() {
         return id;
     }
@@ -545,8 +547,6 @@ public class Apps extends JpaEntity implements Serializable {
         return modifiedDate;
     }
 
-
-
     /**
      * @param modifiedDate the modifiedDate to set
      */
@@ -554,8 +554,6 @@ public class Apps extends JpaEntity implements Serializable {
         this.modifiedDate = modifiedDate;
     }
 
-
-
     public int getStatus() {
         return status;
     }
@@ -572,8 +570,23 @@ public class Apps extends JpaEntity implements Serializable {
         this.inducer = inducer;
     }
     
+    public String getResourceMgt() {
+		return resourceMgt;
+	}
+
+	public void setResourceMgt(String resourceMgt) {
+		this.resourceMgt = resourceMgt;
+	}
+
+	public String getOpenapiRight() {
+		return openapiRight;
+	}
+
+	public void setOpenapiRight(String openapiRight) {
+		this.openapiRight = openapiRight;
+	}
 
-    public String getLogoutUrl() {
+	public String getLogoutUrl() {
         return logoutUrl;
     }
 

+ 49 - 48
maxkey-entity/src/main/java/org/dromara/maxkey/entity/apps/AppsOAuth20Details.java

@@ -90,66 +90,67 @@ public class AppsOAuth20Details extends Apps  implements Serializable {
     /**
      * 
      */
-    public AppsOAuth20Details(Apps application, BaseClientDetails baseClientDetails) {
-        super();
-        this.id = application.getId();
-        this.setAppName(application.getAppName());
-        this.setLoginUrl(application.getLoginUrl());
-        this.setLogoutUrl(application.getLogoutUrl());
-        this.setLogoutType(application.getLogoutType());
-        this.setCategory(application.getCategory());
-        this.setProtocol(application.getProtocol());
-        this.setIcon(application.getIcon());
-        this.clientId = application.getId();
-
-        this.setSortIndex(application.getSortIndex());
-        this.setVendor(application.getVendor());
-        this.setVendorUrl(application.getVendorUrl());
-        this.setVisible(application.getVisible());
+    public static AppsOAuth20Details build(Apps app, BaseClientDetails baseClientDetails) {
+    	AppsOAuth20Details detail = new AppsOAuth20Details();
+    	detail.id = app.getId();
+    	detail.setAppName(app.getAppName());
+    	detail.setLoginUrl(app.getLoginUrl());
+    	detail.setLogoutUrl(app.getLogoutUrl());
+    	detail.setLogoutType(app.getLogoutType());
+    	detail.setCategory(app.getCategory());
+    	detail.setProtocol(app.getProtocol());
+    	detail.setIcon(app.getIcon());
+    	detail.clientId = app.getId();
+
+    	detail.setSortIndex(app.getSortIndex());
+    	detail.setVendor(app.getVendor());
+    	detail.setVendorUrl(app.getVendorUrl());
+    	detail.setVisible(app.getVisible());
         
-        this.setIsAdapter(application.getIsAdapter());
-        this.setAdapter(application.getAdapter());
-        this.setAdapterId(application.getAdapterId());
-        this.setAdapterName(application.getAdapterName());
-        this.setFrequently(application.getFrequently());
-        this.setStatus(application.getStatus());
-        this.setInducer(application.getInducer());
-        this.setExtendAttr(application.getExtendAttr());
-        this.setIsExtendAttr(application.getIsExtendAttr());
+    	detail.setIsAdapter(app.getIsAdapter());
+    	detail.setAdapter(app.getAdapter());
+    	detail.setAdapterId(app.getAdapterId());
+    	detail.setAdapterName(app.getAdapterName());
+    	detail.setFrequently(app.getFrequently());
+    	detail.setStatus(app.getStatus());
+    	detail.setInducer(app.getInducer());
+    	detail.setExtendAttr(app.getExtendAttr());
+    	detail.setIsExtendAttr(app.getIsExtendAttr());
+    	detail.setResourceMgt(app.getResourceMgt());
+    	detail.setOpenapiRight(app.getOpenapiRight());
         
-        this.clientSecret = baseClientDetails.getClientSecret();
-        this.scope = StringUtils
+    	detail.clientSecret = baseClientDetails.getClientSecret();
+    	detail.scope = StringUtils
                 .collectionToCommaDelimitedString(baseClientDetails.getScope());
-        this.resourceIds = StringUtils
+    	detail.resourceIds = StringUtils
                 .collectionToCommaDelimitedString(baseClientDetails.getResourceIds());
-        this.authorizedGrantTypes = StringUtils
+    	detail.authorizedGrantTypes = StringUtils
                 .collectionToCommaDelimitedString(baseClientDetails.getAuthorizedGrantTypes());
-        this.registeredRedirectUris = StringUtils
+    	detail.registeredRedirectUris = StringUtils
                 .collectionToCommaDelimitedString(baseClientDetails.getRegisteredRedirectUri());
-        this.authorities = StringUtils
+    	detail.authorities = StringUtils
                 .collectionToCommaDelimitedString(baseClientDetails.getAuthorities());
-        this.accessTokenValiditySeconds = baseClientDetails.getAccessTokenValiditySeconds();
-        this.refreshTokenValiditySeconds = baseClientDetails.getRefreshTokenValiditySeconds();
-        this.approvalPrompt = baseClientDetails.isAutoApprove("all") + "";
+    	detail.accessTokenValiditySeconds = baseClientDetails.getAccessTokenValiditySeconds();
+    	detail.refreshTokenValiditySeconds = baseClientDetails.getRefreshTokenValiditySeconds();
+    	detail.approvalPrompt = baseClientDetails.isAutoApprove("all") + "";
 
-        this.audience = baseClientDetails.getAudience();
-        this.issuer = baseClientDetails.getIssuer();
-        
-        this.algorithm = baseClientDetails.getAlgorithm();
-        this.algorithmKey = baseClientDetails.getAlgorithmKey();
-        this.encryptionMethod = baseClientDetails.getEncryptionMethod();
+    	detail.audience = baseClientDetails.getAudience();
+    	detail.issuer = baseClientDetails.getIssuer();
         
-        this.signature = baseClientDetails.getSignature();
-        this.signatureKey = baseClientDetails.getSignatureKey();
+    	detail.algorithm = baseClientDetails.getAlgorithm();
+    	detail.algorithmKey = baseClientDetails.getAlgorithmKey();
+    	detail.encryptionMethod = baseClientDetails.getEncryptionMethod();
         
-        this.approvalPrompt = baseClientDetails.getApprovalPrompt();
+    	detail.signature = baseClientDetails.getSignature();
+    	detail.signatureKey = baseClientDetails.getSignatureKey();
         
-        this.pkce = baseClientDetails.getPkce();
-        this.instId = baseClientDetails.getInstId();
-        this.subject = baseClientDetails.getSubject();
-        this.userInfoResponse = baseClientDetails.getUserInfoResponse();
+    	detail.approvalPrompt = baseClientDetails.getApprovalPrompt();
         
-
+    	detail.pkce = baseClientDetails.getPkce();
+    	detail.instId = baseClientDetails.getInstId();
+    	detail.subject = baseClientDetails.getSubject();
+    	detail.userInfoResponse = baseClientDetails.getUserInfoResponse();
+        return detail;
     }
 
     public String getPkce() {

+ 9 - 0
maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/AppsMapper.xml

@@ -21,6 +21,9 @@
 		<if test="vendor != null and vendor != ''">
 			and vendor 		= #{vendor}
 		</if>
+		<if test="resourceMgt != null and resourceMgt != ''">
+			and resourceMgt 		= #{resourceMgt}
+		</if>
 		
 	</sql>
 	
@@ -69,6 +72,8 @@
 			credentials,
 			
 			visible,
+			resourceMgt,
+			openapiRight,
 			
 			sortindex,
 			
@@ -111,6 +116,8 @@
 			#{credentials},
 			
 			#{visible},
+			#{resourceMgt},
+			#{openapiRight},
 			
 			#{sortIndex},
 			
@@ -163,6 +170,8 @@
 			principal			=	#{principal},
 			credentials			=	#{credentials},
 			visible				=	#{visible},
+			resourceMgt			=	#{resourceMgt},
+			openapiRight		=	#{openapiRight},
 			sortindex			=	#{sortIndex},
 			
 			modifiedby			=	#{modifiedBy},

+ 6 - 12
maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestOrganizationController.java

@@ -35,10 +35,8 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.util.UriComponentsBuilder;
 
 @RestController
 @RequestMapping(value={"/api/idm/Organization"})
@@ -49,17 +47,14 @@ public class RestOrganizationController {
     OrganizationsService organizationsService;
     
     @GetMapping(value = "/{id}")
-    public Organizations getUser(@PathVariable String id,
-                                       @RequestParam(required = false) String attributes) {
-        _logger.debug("Organizations id {} , attributes {}", id , attributes);
+    public Organizations getUser(@PathVariable String id) {
+        _logger.debug("Organizations id {} ", id );
         return organizationsService.get(id);
     }
 
     @PostMapping
-    public Organizations create(@RequestBody  Organizations org,
-                                                      @RequestParam(required = false) String attributes,
-                                                      UriComponentsBuilder builder) {
-        _logger.debug("Organizations content {} , attributes {}", org , attributes);
+    public Organizations create(@RequestBody  Organizations org) {
+        _logger.debug("Organizations content {} ", org );
         Organizations loadOrg = organizationsService.get(org.getId());
         if(loadOrg == null) {
             organizationsService.insert(org);
@@ -71,9 +66,8 @@ public class RestOrganizationController {
 
     @PutMapping(value = "/{id}")
     public Organizations replace(@PathVariable String id,
-                                                       @RequestBody Organizations org,
-                                                       @RequestParam(required = false) String attributes) {
-        _logger.debug("Organizations id {} , content {} , attributes {}", id , org , attributes);
+                                                       @RequestBody Organizations org) {
+        _logger.debug("Organizations id {} , content {} ", id , org );
         Organizations loadOrg = organizationsService.get(id);
         if(loadOrg == null) {
             organizationsService.insert(org);

+ 6 - 12
maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestUserInfoController.java

@@ -35,10 +35,8 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.util.UriComponentsBuilder;
 
 @RestController
 @RequestMapping(value={"/api/idm/Users"})
@@ -51,19 +49,16 @@ public class RestUserInfoController {
     
     @GetMapping(value = "/{id}")
     public UserInfo getUser(
-                                       @PathVariable String id,
-                                       @RequestParam(required = false) String attributes) {
-        _logger.debug("UserInfo id {} , attributes {}", id , attributes);
+                                       @PathVariable String id) {
+        _logger.debug("UserInfo id {}", id );
         UserInfo loadUserInfo = userInfoService.get(id);
         loadUserInfo.setDecipherable(null);
         return loadUserInfo;
     }
 
     @PostMapping
-    public UserInfo create(@RequestBody  UserInfo userInfo,
-                                                      @RequestParam(required = false) String attributes,
-                                                      UriComponentsBuilder builder) {
-        _logger.debug("UserInfo content {} , attributes {}", userInfo , attributes);
+    public UserInfo create(@RequestBody  UserInfo userInfo) {
+        _logger.debug("UserInfo content {} ", userInfo );
         UserInfo loadUserInfo = userInfoService.findByUsername(userInfo.getUsername());
         if(loadUserInfo != null) {
             userInfoService.update(userInfo);
@@ -75,9 +70,8 @@ public class RestUserInfoController {
     
     @PutMapping(value = "/{id}")
     public UserInfo replace(@PathVariable String id,
-                                                       @RequestBody UserInfo userInfo,
-                                                       @RequestParam(required = false) String attributes) {
-        _logger.debug("UserInfo content {} , attributes {}", userInfo , attributes);
+                                                       @RequestBody UserInfo userInfo) {
+        _logger.debug("UserInfo content {} ", userInfo );
         UserInfo loadUserInfo = userInfoService.findByUsername(userInfo.getUsername());
         if(loadUserInfo != null) {
             userInfoService.update(userInfo);

+ 16 - 9
maxkey-web-apis/maxkey-web-api-rest/src/main/java/org/dromara/maxkey/web/apis/identity/rest/RestUserPasswordController.java

@@ -19,18 +19,22 @@ package org.dromara.maxkey.web.apis.identity.rest;
 
 import java.io.IOException;
 
+import org.dromara.maxkey.authn.web.AuthorizationUtils;
 import org.dromara.maxkey.entity.ChangePassword;
+import org.dromara.maxkey.entity.Message;
+import org.dromara.maxkey.entity.apps.Apps;
 import org.dromara.maxkey.entity.idm.UserInfo;
+import org.dromara.maxkey.persistence.service.AppsService;
 import org.dromara.maxkey.persistence.service.UserInfoService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.User;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.util.UriComponentsBuilder;
 
 @Controller
 @RequestMapping(value={"/api/idm/Users"})
@@ -41,23 +45,26 @@ public class RestUserPasswordController {
     @Autowired
     UserInfoService userInfoService;
     
-  
+    @Autowired
+    AppsService appsService;
+    
     @PostMapping(value = "/changePassword")
     @ResponseBody
-    public String changePassword(@RequestParam(required = true) String username,
-                                 @RequestParam(required = true) String password,
-                                 UriComponentsBuilder builder) throws IOException {
-        
+    public Message<Boolean> changePassword(@RequestParam(required = true) String username,
+                                 @RequestParam(required = true) String password) throws IOException {
         _logger.debug("UserInfo username {} , password {}", username , password);
-        
-        UserInfo loadUserInfo = userInfoService.findByUsername(username);
+        //获取认证的应用的信息
+        User  principal = (User)AuthorizationUtils.getAuthentication().getPrincipal();
+        Apps app = appsService.get(principal.getUsername());
+        UserInfo loadUserInfo = userInfoService.findByUsernameAndInstId(username,app.getInstId());
         if(loadUserInfo != null) {
             ChangePassword changePassword  = new ChangePassword(loadUserInfo);
             changePassword.setPassword(password);
             changePassword.setDecipherable(loadUserInfo.getDecipherable());
             userInfoService.changePassword(changePassword,true);
+            return new Message<>(Message.SUCCESS,"Change password success",true);
         }
-        return "true";
+        return new Message<>(Message.FAIL,"Change password fail",false);
     }
 
 }

+ 1 - 1
maxkey-web-frontend/maxkey-web-app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "maxkey",
-  "version": "4.1.x",
+  "version": "4.2.x",
   "description": "Leading-Edge IAM Identity and Access Management",
   "author": "MaxKey <support@maxsso.net>",
   "repository": {

+ 1 - 1
maxkey-web-frontend/maxkey-web-mgt-app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "maxkey",
-  "version": "4.1.x",
+  "version": "4.2.x",
   "description": "Leading-Edge IAM Identity and Access Management",
   "author": "MaxKey <support@maxsso.net>",
   "repository": {

+ 1 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/entity/Apps.ts

@@ -41,6 +41,7 @@ export class Apps extends BaseEntity {
   isExtendAttr!: String;
   extendAttr!: String;
   resourceMgt!: String;
+  openapiRight!: String;
   userPropertys!: String;
   isSignature!: String;
   isAdapter!: String;

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-basic-details-editer/app-basic-details-editer.component.html

@@ -224,6 +224,31 @@
         </div>
         <div nz-row>
           <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
+          <nz-form-item>
             <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="isAdapter">{{ 'mxk.apps.isAdapter' | i18n }}</nz-form-label>
             <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid isAdapter!">
               <nz-select [(ngModel)]="form.model.isAdapter" [ngModelOptions]="{ standalone: true }" name="isAdapter" id="isAdapter">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-cas-details-editer/app-cas-details-editer.component.html

@@ -314,6 +314,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-extend-api-details-editer/app-extend-api-details-editer.component.html

@@ -352,6 +352,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-form-based-details-editer/app-form-based-details-editer.component.html

@@ -419,6 +419,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-jwt-details-editer/app-jwt-details-editer.component.html

@@ -437,6 +437,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-oauth20-details-editer/app-oauth20-details-editer.component.html

@@ -545,6 +545,31 @@
         </div>
         <div nz-row>
           <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
+          <nz-form-item>
             <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="inducer">{{ 'mxk.apps.inducer' | i18n }}</nz-form-label>
             <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid inducer!">
               <nz-select [(ngModel)]="form.model.inducer" [ngModelOptions]="{ standalone: true }" name="isAdapter" id="inducer">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-saml20-details-editer/app-saml20-details-editer.component.html

@@ -504,6 +504,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="20" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/apps/app-token-based-details-editer/app-token-based-details-editer.component.html

@@ -369,6 +369,31 @@
           </nz-form-item>
         </div>
         <div nz-row>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="resourceMgt">{{ 'mxk.apps.resourceMgt' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid resourceMgt!">
+              <nz-select [(ngModel)]="form.model.resourceMgt" [ngModelOptions]="{ standalone: true }" name="resourceMgt" id="resourceMgt">
+                <nz-option nzValue="n" nzLabel="{{ 'mxk.text.no' | i18n }}"></nz-option>
+                <nz-option nzValue="y" nzLabel="{{ 'mxk.text.yes' | i18n }}"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label [nzSm]="8" [nzXs]="24" nzFor="openapiRight">{{ 'mxk.apps.openapiRight' | i18n }}</nz-form-label>
+            <nz-form-control [nzSm]="16" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid openapiRight!">
+              <nz-select
+                [(ngModel)]="form.model.openapiRight"
+                [ngModelOptions]="{ standalone: true }"
+                name="openapiRight"
+                id="openapiRight"
+              >
+                <nz-option nzValue="read" nzLabel="Read"></nz-option>
+                <nz-option nzValue="write" nzLabel="Write"></nz-option>
+              </nz-select>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-row>
           <nz-form-item style="width: 100%">
             <nz-form-label [nzSm]="4" [nzXs]="24" nzFor="description">{{ 'mxk.text.description' | i18n }} </nz-form-label>
             <nz-form-control [nzSm]="20" [nzMd]="16" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid description!">

+ 27 - 25
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.ts

@@ -39,6 +39,7 @@ export class AppsComponent implements OnInit {
       appName: String;
       displayName: String;
       protocol: String;
+      resourceMgt: String;
       startDate: String;
       endDate: String;
       startDatePicker: Date;
@@ -58,29 +59,30 @@ export class AppsComponent implements OnInit {
     indeterminate: boolean;
     checked: boolean;
   } = {
-      params: {
-        appName: '',
-        displayName: '',
-        protocol: '',
-        startDate: '',
-        endDate: '',
-        startDatePicker: addDays(new Date(), -30),
-        endDatePicker: new Date(),
-        pageSize: 10,
-        pageNumber: 1,
-        pageSizeOptions: [10, 20, 50]
-      },
-      results: {
-        records: 0,
-        rows: []
-      },
-      expandForm: false,
-      submitLoading: false,
-      tableLoading: false,
-      tableCheckedId: new Set<String>(),
-      indeterminate: false,
-      checked: false
-    };
+    params: {
+      appName: '',
+      displayName: '',
+      protocol: '',
+      resourceMgt: 'y',
+      startDate: '',
+      endDate: '',
+      startDatePicker: addDays(new Date(), -30),
+      endDatePicker: new Date(),
+      pageSize: 10,
+      pageNumber: 1,
+      pageSizeOptions: [10, 20, 50]
+    },
+    results: {
+      records: 0,
+      rows: []
+    },
+    expandForm: false,
+    submitLoading: false,
+    tableLoading: false,
+    tableCheckedId: new Set<String>(),
+    indeterminate: false,
+    checked: false
+  };
 
   constructor(
     private modalService: NzModalService,
@@ -91,7 +93,7 @@ export class AppsComponent implements OnInit {
     @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
     private router: Router,
     private cdr: ChangeDetectorRef
-  ) { }
+  ) {}
 
   ngOnInit(): void {
     this.fetch();
@@ -107,7 +109,7 @@ export class AppsComponent implements OnInit {
     this.fetch();
   }
 
-  onReset(): void { }
+  onReset(): void {}
 
   onEditPermission(e: MouseEvent, appId: String, appName: String): void {
     this.router.navigateByUrl(`/permissions/apps/permission?appId=${appId}&appName=${appName}`);

+ 2 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json

@@ -279,6 +279,8 @@
 			"tab.custom": "Custom",
 			"extendapi.tab": "API",
 			"resources":"Resources",
+      "resourceMgt": "Resource Management",
+      "openapiRight": "OpenAPI Right",
 			"permission":"Permission",
 			"role":"Roles",
 			"id": "App Id",

+ 2 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json

@@ -280,6 +280,8 @@
 			"tab.custom": "自定义属性",
 			"extendapi.tab": "API配置",
 			"resources":"资源",
+      "resourceMgt": "资源管理",
+      "openapiRight": "OpenAPI 权限",
 			"permission":"权限",
 			"role":"角色",
 			"id": "应用编码",

+ 2 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json

@@ -281,6 +281,8 @@
 			"tab.custom": "自訂屬性",
 			"extendapi.tab": "API配置",
 			"resources":"資源",
+      "resourceMgt": "資源管理",
+      "openapiRight": "OpenAPI 權限",
 			"permission":"權限",
 			"role":"角色",
 			"id": "應用編碼",

+ 1 - 1
maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/web/apps/controller/OAuth20DetailsController.java

@@ -65,7 +65,7 @@ public class OAuth20DetailsController  extends BaseAppContorller {
         BaseClientDetails baseClientDetails=(BaseClientDetails)oauth20JdbcClientDetailsService.loadClientByClientId(id,false);
         Apps application=appsService.get(id);//
         decoderSecret(application);
-        AppsOAuth20Details oauth20Details=new AppsOAuth20Details(application,baseClientDetails);
+        AppsOAuth20Details oauth20Details= AppsOAuth20Details.build(application,baseClientDetails);
         oauth20Details.setSecret(application.getSecret());
         oauth20Details.setClientSecret(application.getSecret());
         logger.debug("forwardUpdate {}" , oauth20Details);

+ 18 - 17
maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/web/interceptor/RestApiPermissionAdapter.java

@@ -67,17 +67,16 @@ public class RestApiPermissionAdapter  implements AsyncHandlerInterceptor  {
     public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
         logger.trace("Rest API Permission Adapter pre handle");
          AuthorizationHeader headerCredential = AuthorizationHeaderUtils.resolve(request);
-         
+         Apps app = null;
         //判断应用的AppId和Secret
         if(headerCredential != null){
             UsernamePasswordAuthenticationToken authenticationToken = null;
             if(headerCredential.isBasic()) {
-                if(StringUtils.isNotBlank(headerCredential.getUsername())&&
-                        StringUtils.isNotBlank(headerCredential.getCredential())
-                        ) {
+                if(StringUtils.isNotBlank(headerCredential.getUsername())
+                		&& StringUtils.isNotBlank(headerCredential.getCredential())) {
                     String appId = headerCredential.getUsername();
                     String credential = headerCredential.getCredential();
-                    Apps app = appsService.get(appId, true);
+                    app = appsService.get(appId, true);
                     if(app != null ) {
                         if(    PasswordReciprocal.getInstance().matches(credential, app.getSecret())) {
                             ArrayList<SimpleGrantedAuthority> grantedAuthoritys = new ArrayList<>();
@@ -93,25 +92,27 @@ public class RestApiPermissionAdapter  implements AsyncHandlerInterceptor  {
                 }
             }else if(StringUtils.isNotBlank(headerCredential.getCredential())){
                 logger.trace("Authentication bearer {}" , headerCredential.getCredential());
-                OAuth2Authentication oauth2Authentication = 
-                        oauth20TokenServices.loadAuthentication(headerCredential.getCredential());
-                
+                OAuth2Authentication oauth2Authentication = oauth20TokenServices.loadAuthentication(headerCredential.getCredential());
                 if(oauth2Authentication != null) {
+                	//使用clientId作为用户名,应用密码作为密码
                     logger.trace("Authentication token {}" , oauth2Authentication.getPrincipal().toString());
-                    authenticationToken= new UsernamePasswordAuthenticationToken(
-                            new User(
-                                    oauth2Authentication.getPrincipal().toString(), 
-                                    "CLIENT_SECRET", 
-                                    oauth2Authentication.getAuthorities()), 
-                            "PASSWORD", 
-                            oauth2Authentication.getAuthorities()
-                    );
+                    app = appsService.get(oauth2Authentication.getPrincipal().toString(), true);
+                    User user = new User(oauth2Authentication.getPrincipal().toString(), "CLIENT_SECRET", oauth2Authentication.getAuthorities());
+                    authenticationToken= new UsernamePasswordAuthenticationToken(user, "PASSWORD", oauth2Authentication.getAuthorities());
                 }else {
                     logger.trace("Authentication token is null ");
                 }
             }
             
-            if(authenticationToken !=null && authenticationToken.isAuthenticated()) {
+            if(authenticationToken !=null && authenticationToken.isAuthenticated() && app != null) {
+            	if("read".equalsIgnoreCase(app.getOpenapiRight())) {
+					if(request.getMethod().equalsIgnoreCase("GET")) {
+						AuthorizationUtils.setAuthentication(authenticationToken);
+		                return true;
+					}else {
+						return false;
+					}
+            	}
                 AuthorizationUtils.setAuthentication(authenticationToken);
                 return true;
             }