首頁>技術>

本文是在《Spring Cloud OAuth2實現使用者認證中心學習筆記》的基礎上擴充套件的,本文的程式碼也是與其程式碼配套使用。

1、在上文的AuthenticationServer專案中增加UserDetailsController用於獲取當前使用者資訊

1、在SpringCloudOAuth2Server專案中建立一個包com.wongoing.oauth2.controller2、在com.wongoing.oauth2.controller包下建立一個類UserDetailsController.java,程式碼如下:

package com.wongoing.oauth2.controller;import java.security.Principal;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;/** * 功能說明:使用者資訊API * 修改說明: * @author zheng * @date 2021-1-22 15:18:20 * @version 0.1 */@RestController@RequestMapping("/users")public class UserDetailsController { /** * 功能說明:獲取當前使用者資訊 * 修改說明: * @author zheng * @date 2021-1-22 15:18:04 * @param principal * @return */ @RequestMapping(value = "/current", method = RequestMethod.GET) public Principal getUser(Principal principal) { return principal; }}

2、為上文的AuthenticationServer專案啟動類增加@EnableResourceServer註解

因為上面/users/current也相當於一個資源,要走認證中心則需要把當前專案也配置為Resource Server。

啟動類是com.wongoing.SpringCloudOAuth2ServerApplication.java,增加@EnableResourceServer註解後代碼如下:

package com.wongoing;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;@SpringBootApplication@EnableResourceServerpublic class SpringCloudOAuth2ServerApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudOAuth2ServerApplication.class, args); }}

4、修改spring配置

對專案中的application.properties檔案進行重新命名為application.yml,配置的內容如下:

server: port: 9001spring: application: name: resource-service security: oauth2: resource: user-info-uri: http://localhost:8080/users/current

5、建立需要鑑權訪問的API介面(Resource)

1、在當前專案中建立一個包com.wongoing.controller2、在com.wongoing.controller包下建立一個控制器類TestController.java,程式碼如下:

package com.wongoing.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test")public class TestController { @Value("${server.port}") private String port; @GetMapping("/serverport") public String getPort() { return "當前伺服器埠:" + this.port; } @RequestMapping("/1") public String test1() { return "這是測試介面1"; } @RequestMapping("/2") public String test2() { return "這是測試介面2"; }}

上面的控制器類定義了3個API介面,我們想實現ADMIN角色的使用者可以訪問所有這3個介面,USER角色的使用者只能訪問第一個介面。

6、實現ResourceServer

1、在專案中建立一個包com.wongoing.oauth2.config

6.1 自定義路徑攔截處理類實現FilterInvocationSecurityMetadataSource介面

我這裡用的類名是com.wongoing.oauth2.config.TheFilterSecurityMetadataSource.java,程式碼如下:

package com.wongoing.oauth2.config;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.SecurityConfig;import org.springframework.security.web.FilterInvocation;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import org.springframework.stereotype.Component;/** * 功能說明:路徑攔截處理類 * 修改說明: * @author zheng * @date 2021-1-22 9:52:27 * @version 0.1 */@Componentpublic class TheFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { //定義角色的許可權列表,實際應該從資料庫取,這裡為了簡化程式先寫死 private Map<String, List<String>> rolePermissions = new HashMap<String, List<String>>() {{ put("ADMIN", new ArrayList() {{ add("/test/serverport"); add("/test/1"); add("/test/2");}}); //ADMIN角色有3個API的訪問許可權 put("USER", new ArrayList() {{ add("/test/serverport"); }}); //USER只有/test/serverport這1個API的訪問許可權 }}; @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { FilterInvocation fi = (FilterInvocation)object; //當前請求物件 if (this.isMatcherAllowedRequest(fi)) { return null; //return null 表示允許訪問,不做攔截 } List<ConfigAttribute> configAttributes = this.getMatcherConfigAttribute(fi.getRequestUrl()); return configAttributes.size() > 0 ? configAttributes : this.deniedRequest(); //返回當前路徑所需角色,如果沒有則拒絕訪問 } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { // TODO Auto-generated method stub return null; } @Override public boolean supports(Class<?> clazz) { // TODO Auto-generated method stub return FilterInvocation.class.isAssignableFrom(clazz); } /** * 功能說明:獲取當前路徑所需要的角色 * 修改說明: * @author zheng * @date 2021-1-22 10:02:55 * @param url 當前路徑 * @return 所需角色集合 */ private List<ConfigAttribute> getMatcherConfigAttribute(String url) { List<ConfigAttribute> roles = new ArrayList<ConfigAttribute>(); for (String role : this.rolePermissions.keySet()) { List<String> uriList = this.rolePermissions.get(role); for (String uri : uriList) { if (url.contains(uri)) { roles.add(new SecurityConfig(role)); break; } } } return roles; } /** * 功能說明:判斷當前請求是否在允許請求的範圍內 * 修改說明: * @author zheng * @date 2021-1-22 10:12:16 * @param fi 當前請求 * @return 是否在範圍中 */ private boolean isMatcherAllowedRequest(FilterInvocation fi) { boolean result = this.allowedRequest().stream().map(AntPathRequestMatcher::new) .filter(requestMatcher -> requestMatcher.matches(fi.getHttpRequest())) .toArray().length > 0; return result; } /** * 功能說明:定義允許請求的列表 * 修改說明: * @author zheng * @date 2021-1-22 10:09:56 * @return */ public List<String> allowedRequest() { return Arrays.asList("/login", "/hello"); } /** * 功能說明:預設拒絕訪問配置 * 修改說明: * @author zheng * @date 2021-1-22 10:09:32 * @return */ public List<ConfigAttribute> deniedRequest() { return Collections.singletonList(new SecurityConfig("ROLE_DENIED")); //預設需要的角色 }}

6.2 自定義許可權決策處理類實現AccessDecisionManager介面

我這裡用的類名是com.wongoing.oauth2.config.TheAccessDecisionManager.java,程式碼如下:

package com.wongoing.oauth2.config;import java.util.Collection;import java.util.List;import java.util.stream.Collectors;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.authentication.InsufficientAuthenticationException;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;import org.springframework.stereotype.Component;/** * 功能說明:許可權決策處理類 * 修改說明: * @author zheng * @date 2021-1-22 9:53:58 * @version 0.1 */@Componentpublic class TheAccessDecisionManager implements AccessDecisionManager { /** * 決定 */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (authentication == null) { throw new AccessDeniedException("permission denied"); } //當前使用者擁有的角色集合 List<String> roleCodes = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); //訪問路徑所需要的角色集合 List<String> configRoleCodes = configAttributes.stream().map(ConfigAttribute::getAttribute).collect(Collectors.toList()); for (String roleCode : roleCodes) { if (configRoleCodes.contains(roleCode)) { return; } } throw new AccessDeniedException("permission denied"); } @Override public boolean supports(ConfigAttribute attribute) { // TODO Auto-generated method stub return false; } @Override public boolean supports(Class<?> clazz) { // TODO Auto-generated method stub return false; }}

6.3 定義ResourceServer配置類繼承ResourceServerConfigurerAdapter

我這裡的類名是com.wongoing.oauth2.config.ResourceServerConfig.java,程式碼如下:

package com.wongoing.oauth2.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.config.annotation.ObjectPostProcessor;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;/** * 功能說明:資源伺服器配置類 * 修改說明: * @author zheng * @date 2021-1-22 9:28:28 * @version 0.1 */@Configuration@EnableResourceServer@EnableGlobalMethodSecurity(prePostEnabled = true)public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private AccessDecisionManager accessDecisionManager; @Autowired private FilterInvocationSecurityMetadataSource filterSecurityMetadataSource; @Override public void configure(HttpSecurity http) throws Exception { http.formLogin().loginPage("/login").defaultSuccessUrl("/", true) .and() .exceptionHandling().accessDeniedPage("/error") .and() .csrf().disable() .authorizeRequests() // 對使用者註冊的URL地址開放 .antMatchers("/users/register").permitAll() //其餘介面沒有角色限制,但需要經過認證,只要攜帶token就可以放行 .anyRequest() .authenticated() .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { @Override public <O extends FilterSecurityInterceptor> O postProcess(O object) { object.setAccessDecisionManager(accessDecisionManager); //許可權決策處理類 object.setSecurityMetadataSource(filterSecurityMetadataSource); //路徑(資源)攔截處理 return object; } }); }}

7、API鑑權測試

根據《Spring Cloud OAuth2實現使用者認證中心學習筆記》中的UserDetailsServiceBean.java中程式碼可以看出我這裡模擬資料庫中有2個使用者分別是admin和zheng,其中admin的角色是ADMIN,zheng的角色是USER。

/** * 功能說明:透過@PostConstruct定義Bean初始化方法 * 修改說明: * @author zheng * @date 2021-1-19 16:39:55 */@PostConstructpublic void init() { //生成測試資料 this.users = new HashMap<String, User>() {{ put("admin", new User(1L, "admin", passwordEncoder.encode("456"), new ArrayList() {{ add(new Role(1L, "ADMIN")); }})); put("zheng", new User(2L, "zheng", passwordEncoder.encode("789"), new ArrayList() {{ add(new Role(2L, "USER")); }})); }};}

7.1 測試ADMIN角色的許可權

1、先在postman中透過以下訪問路徑獲取admin使用者的access_token

http://localhost:8080/oauth/token?grant_type=password&client_id=webApp&client_secret=123&username=admin&password=456

如下圖:

這裡獲得的admin使用者的access_token的值是

aaf1903a-92b8-4ef4-8bd2-0f9199d0fed9

2、使用上面的access_token在postman中測試第1個介面/test/serverport測試地址如下:

http://localhost:9001/test/serverport?access_token=aaf1903a-92b8-4ef4-8bd2-0f9199d0fed9

如下圖:

可以看到admin獲得的access_token訪問這個介面是成功的。3、使用上面的access_token在postman中測試第2個介面/test/1測試地址如下:

http://localhost:9001/test/1?access_token=aaf1903a-92b8-4ef4-8bd2-0f9199d0fed9

結果如下圖:

可以看到admin獲得的access_token訪問這個介面也是成功的。4、使用上面的access_token在postman中測試第3個介面/test/2測試地址如下:

http://localhost:9001/test/2?access_token=aaf1903a-92b8-4ef4-8bd2-0f9199d0fed9

結果如下圖:

可以看到admin獲得的access_token訪問這個3介面都是成功的。

7.2 測試USER角色的許可權

1、先在postman中透過以下訪問路徑獲取zheng使用者的access_token

http://localhost:8080/oauth/token?grant_type=password&client_id=webApp&client_secret=123&username=zheng&password=789

如下圖:

這裡獲得的zheng使用者的access_token的值是

bea23144-1ddd-4bcd-8ffe-e4b71a9d791c

2、使用上面的access_token在postman中測試第1個介面/test/serverport測試地址如下:

http://localhost:9001/test/serverport?access_token=bea23144-1ddd-4bcd-8ffe-e4b71a9d791c

如下圖:

可以看到zheng獲得的access_token訪問這個介面是成功的。3、使用上面的access_token在postman中測試第2個介面/test/1測試地址如下:

http://localhost:9001/test/1?access_token=bea23144-1ddd-4bcd-8ffe-e4b71a9d791c

結果如下圖:

可以看到zheng獲得的access_token訪問這個介面是失敗的,說明許可權不夠。4、使用上面的access_token在postman中測試第3個介面/test/2測試地址如下:

http://localhost:9001/test/2?access_token=bea23144-1ddd-4bcd-8ffe-e4b71a9d791c

結果如下圖:

可以看到zheng獲得的access_token訪問這個介面是失敗的,說明許可權不夠。

8、總結

透過這2篇文章,我們實現了基於Spring Cloud OAuth2的使用者認證與API鑑權功能,希望對各位學習的朋友能有所幫助。《Spring Cloud OAuth2實現使用者認證中心學習筆記》

本文連結:

https://blog.csdn.net/zlbdmm/article/details/112985445

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Vue2.x原始碼之生命週期