SpringBoot的Security和OAuth2的使用示例小結
創(chuàng)建項目
先創(chuàng)建一個spring項目。
然后編寫pom文件如下,引入spring-boot-starter-security,我這里使用的spring boot是2.4.2,這里使用使用spring-boot-dependencies,在這里就能找到對應的security的包。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>app-kiba-security</artifactId> <version>0.0.1-SNAPSHOT</version> <name>app-kiba-security</name> <description>app-kiba-security</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.4.2</spring-boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <mainClass>com.kiba.appkibasecurity.AppKibaSecurityApplication</mainClass> <skip>true</skip> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
然后訪問創(chuàng)建項目時默認生成的接口:http://127.0.0.1:8080/user/123/roles/222,得到如下界面。
這是相當于,在我們的接口請求的前面做了一個攔截,類似filter,攔截后,跳轉到了一個界面,讓我們輸入賬號密碼。這里,我由于沒有設置賬號密碼,所以登錄不進去。
設置訪問一
下面設置一個賬號密碼,并且設置hello接口可以直接訪問,設置很簡單,就是注入兩個bean,InMemoryUserDetailsManager和WebSecurityCustomizer,代碼如下:
@Configuration public class SecurityConfig { /** * 注冊用戶,這里用戶是在內存中的 * {noop}表示“無操作”(No Operation)密碼編碼。 * @return */ @Bean UserDetailsService userDetailsService() { InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(); users.createUser(User.withUsername("kiba").password("{noop}123").roles("admin").build()); return users; } /** * 讓hello可以不用登錄,就可以直接訪問,例如:http://127.0.0.1:8080/hello?name=kiba就可以直接訪問 * @return */ @Bean WebSecurityCustomizer webSecurityCustomizer() { return new WebSecurityCustomizer() { @Override public void customize(WebSecurity web) { web.ignoring().antMatchers("/hello"); } }; } }
現(xiàn)在我們訪問http://127.0.0.1:8080/user/123/roles/222,進入到登錄頁面,輸入kiba/123就可以查看接口執(zhí)行的結果了。
http://127.0.0.1:8080/hello?name=kiba就無需登錄,可以直接訪問。
登錄一次,其他接口就可以自由訪問了
控制請求
現(xiàn)在,增加一個類SecurityAdapter,繼承自WebSecurityConfigurerAdapter。然后重寫他的configure方法
@Configuration @AllArgsConstructor public class SecurityAdapter extends WebSecurityConfigurerAdapter { /** * authenticated():用戶需要通過用戶名/密碼登錄,記住我功能也可以(remember-me)。 * fullyAuthenticated()用戶需要通過用戶名/密碼登錄,記住我功能不行。 */ @Override @SneakyThrows protected void configure(HttpSecurity http) { http.httpBasic().and() //禁用跨站請求偽造(CSRF)保護。 .csrf().disable() .authorizeRequests().anyRequest().fullyAuthenticated(); } }
當使用,增加了SecurityAdapter后,我們重新請求http://127.0.0.1:8080/user/123/roles/222,得到界面如下:
可以看到,登錄界面的樣式被美化了。
設置訪問二(推薦)
我們還可以使用第二種方法,來做用戶密碼的配置。
通過重寫configure(AuthenticationManagerBuilder auth)函數(shù),來創(chuàng)建用戶,這種方式創(chuàng)建用戶會將前面的bean-UserDetailsService給覆蓋,即,用戶只剩下這里創(chuàng)建的。
代碼如下:
@Configuration @AllArgsConstructor public class SecurityAdapter extends WebSecurityConfigurerAdapter { /** * authenticated():用戶需要通過用戶名/密碼登錄,記住我功能也可以(remember-me)。 * fullyAuthenticated()用戶需要通過用戶名/密碼登錄,記住我功能不行。 */ @Override @SneakyThrows protected void configure(HttpSecurity http) { http.httpBasic().and() //禁用跨站請求偽造(CSRF)保護。 .csrf().disable() .authorizeRequests().anyRequest().fullyAuthenticated(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("kiba518") .password(passwordEncoder().encode("123")) .authorities(new ArrayList<>(0)); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
這里的用戶是寫死的,用戶是可以修改成讀取數(shù)據(jù)庫的信息的。
我們查看WebSecurityConfigurerAdapter的代碼,可以看到他有注解@Order(100),數(shù)越大,執(zhí)行越優(yōu)先級越低,即,他的執(zhí)行順序是相對比較靠后的。
授權OAuth2
授權這個設計理念是這樣,它是結合上面的security的操作,實現(xiàn)了一個普通的WebApp轉換成授權服務器WebApp。
授權服務器轉換思路
我們先了解一下security轉授權服務器的思路。
1,在這個應用里,創(chuàng)建一個auth接口,然后任何人想訪問這個接口,就都需要輸入賬戶密碼了。
2,我們這個auth接口的返回值是個code,然后我們的前端,或者其他調用接口的APP,就可以把這個code作為用戶登錄的token了,。
3,然后我們再做一個接口,接受一個token參數(shù),可以驗證token是否有效。
這樣我們這個授權服務器的搭建思路就構建完成了。
但按這個思路,我們需要做很多操作,比如創(chuàng)建接口,緩存token等等,現(xiàn)在spring提供了一個Oauth2的包,他可以幫我們實現(xiàn)這些接口定義。
OAuth2的接口如下,可以自行研究。
/oauth/authorize:授權端點
/oauth/token:獲取令牌端點
/oauth/confirm_access:用戶確認授權提交端點
/oauth/error:授權服務錯誤信息端點
/oauth/check_token:用于資源服務訪問的令牌解析端點
/oauth/token_key:提供公有密匙的端點,如果使用JWT令牌的話
實現(xiàn)授權服務器
現(xiàn)在我們實現(xiàn)一個授權服務器。
先添加OAuth2的引用。
<dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.4.0.RELEASE</version> </dependency>
然后增加配置文件AuthorizationConfig。
@Configuration @EnableAuthorizationServer //開啟授權服務 public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Autowired private AuthenticationManager authenticationManager; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { //允許表單提交 security.allowFormAuthenticationForClients() .checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client-kiba") //客戶端唯一標識(client_id) .secret(passwordEncoder.encode("kiba518-123456")) //客戶端的密碼(client_secret),這里的密碼應該是加密后的 .authorizedGrantTypes("password") //授權模式標識,共4種模式[授權碼(authorization-code)隱藏式(implicit) 密碼式(password)客戶端憑證(client credentials)] .scopes("read_scope"); //作用域 } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } }
然后打開SecurityAdapter,增加一個bean,如下,目的是讓上面的AuthorizationConfig里Autowired的authenticationManager可以實例化。
@Bean public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); }
然后使用APIFox調用一下/oauth/token接口。
先選擇auth,輸入賬號密碼,這個賬號密碼就是AuthorizationConfig里配置的客戶端id和密碼。
這個數(shù)據(jù)在請求時,會進行base64編碼,然后以http的header屬性Authorization的值的模式傳遞,如下。
然后輸入?yún)?shù),參數(shù)里scope和grant_type要和AuthorizationConfig里定義的scopes和authorizedGrantTypes一樣,如下。
請求后,得到結果,如上圖。
我們得到"access_token": "19d37af2-6e13-49c3-bf19-30a738b56886"。
有了access_token后,我們的前端其實就已經可以進行各種騷操作了。
資源服務
這個是Oauth為我們提供的一項很好用的功能。
我們創(chuàng)建一個項目做為資源服務。
添加依賴,版本與上面相同。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.4.0.RELEASE</version> </dependency>
然后編寫資源配置,代碼如下:
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Bean public RemoteTokenServices remoteTokenServices() { final RemoteTokenServices tokenServices = new RemoteTokenServices(); tokenServices.setClientId("client-kiba"); tokenServices.setClientSecret("kiba518-123456"); tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");//這個接口是oauth自帶的 return tokenServices; } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { //session創(chuàng)建策略 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); //所有請求需要認證 http.authorizeRequests().anyRequest().authenticated(); } }
因為添加了spring-boot-starter-security,所以,我們請求這個資源WebApp,就都需要輸入賬號密碼。
但因為,我們配置了ResourceServerConfig,這里我們配置了遠程token服務,設置的信息是我們上面創(chuàng)建授權服務的信息。所以,在訪問這個WebApp時,我們提供token即可。
使用APIFOX測試,先添加auth的token,內容是來自于上面,/oauth/token的返回值access_token的值。
然后請求user接口,我這user接口沒有參數(shù),請求結果如下:
總結
這個授權服務挺好用的,就是配置太繁瑣了,初學者不太好理解,而且功能太多,配置太鬧心。
這個資源服務還是很貼心的,他提我們實現(xiàn)了,tokencheck的部分,但要注意的是,他這tokencheck是基于http請求的。
雖然Oath很好用,但,我還是覺得,這個認證部分自己寫比較好,我們可以根據(jù)項目的需求,設計輕量級的授權認證。
比如,我們想減少http請求,把部分tokencheck在緩存內進行check,那使用oauth時,修改起來就會很頭疼。如果是自己寫的授權服務器,就不會有修改困難的問題。
注:此文章為原創(chuàng),任何形式的轉載都請聯(lián)系作者獲得授權并注明出處!
https://www.cnblogs.com/kiba/p/18252859
到此這篇關于SpringBoot的Security和OAuth2的使用的文章就介紹到這了,更多相關SpringBoot的Security和OAuth2的使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- SpringBoot3.X配置OAuth的代碼實踐
- 使用Springboot實現(xiàn)OAuth服務的示例詳解
- SpringBoot淺析安全管理之OAuth2框架
- springboot oauth2實現(xiàn)單點登錄實例
- springboot集成springsecurity 使用OAUTH2做權限管理的教程
- 基于SpringBoot整合oauth2實現(xiàn)token認證
- springboot2.x實現(xiàn)oauth2授權碼登陸的方法
- 詳解Springboot Oauth2 Server搭建Oauth2認證服務
- 使用Springboot搭建OAuth2.0 Server的方法示例
- SpringBoot集成OAuth2.0的實現(xiàn)示例
相關文章
使用Java實現(xiàn)在Excel中添加動態(tài)數(shù)組公式
動態(tài)數(shù)組公式是?Excel?引入的一項重要功能,它允許用戶從單個單元格中的公式返回多個結果值,并將這些值自動填充到與公式單元格相鄰的單元格中,本文主要介紹了如何使用Java實現(xiàn)在Excel中添加動態(tài)數(shù)組公式,x需要的可以參考下2023-12-12Servlet和Spring?MVC的區(qū)別及使用說明
這篇文章詳細介紹了Servlet和SpringMVC的基本概念、工作原理、功能對比和應用場景,Servlet是JavaWeb開發(fā)的基礎,而SpringMVC是一個基于Servlet的高級框架,提供了更強大的功能和易用性,文章通過定義、原理和示例代碼,幫助讀者理解這兩個技術的區(qū)別與聯(lián)系2025-01-01k8s部署的java服務添加idea調試參數(shù)的方法
文章介紹了如何在K8S容器中的Java服務上進行遠程調試,包括配置Deployment、Service以及本地IDEA的調試設置,感興趣的朋友跟隨小編一起看看吧2025-02-02Spring Boot整合QueryDSL的實現(xiàn)示例
這篇文章主要介紹了Spring Boot整合QueryDSL的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09利用Java實現(xiàn)圖片轉化為ASCII圖的示例代碼
本文將詳細講解如何利用 Java 實現(xiàn)圖片轉化為 ASCII 圖,從項目背景與意義、相關技術知識,到系統(tǒng)需求與架構設計,再到詳細實現(xiàn)思路、完整代碼和代碼解讀,最后對項目進行總結與展望,需要的朋友可以參考下2025-03-03