日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Security + OAuth2.0

發布時間:2023/12/14 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Security + OAuth2.0 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

授權服務器


授權服務器中有4個端點。說明如下:

  • Authorize Endpoint :授權端點,進行授權。
  • Token Endpoint :令牌端點,經過授權拿到對應的Token。
  • lntrospection Endpoint :校驗端點,校驗Token的合法性。
  • Revocation Endpoint :撤銷端點,撤銷授權。

Spring Security Oauth2架構


說明如下:

  • 用戶訪問,此時沒有Token。Oauth2RestTemplate會報錯,這個報錯信息會被Oauth2ClientContextFilter捕獲并重定向到認證服務器。
  • 認證服務器通過Authorization Endpoint進行授權,并通過AuthorizationServerTokenServices生成授權碼并返回給客戶端。
  • 客戶端拿到授權碼去認證服務器通過Token Endpoint調用AuthorizationServerTokenServices生成Token并返回給客戶端。
  • 客戶端拿到Token去資源服務器訪問資源,一般會通過Oauth2AuthenticationManager調用ResourceServerTokenServices進行校驗。校驗通過可以獲取資源。

Spring Security Oauth2授權碼模式

環境搭建

(2)pom依賴

<!-- spring cloud中的oauth2依賴 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><!-- spring cloud中的security依賴 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId></dependency><!-- web模塊 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

(3)pojo
在pojo包下自定一個實體類User,但是此類必實現UserDetails接口。如下:

package com.sec.kun.pojo;import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection; import java.util.List;/*** @Author zhoukun* @Date 2021/2/17 15:45*/ /** 自定義User類,需實現UserDetails接口*/ public class User implements UserDetails {private String username;private String password;private List<GrantedAuthority> authorities;// 構造方法public User(String username, String password, List<GrantedAuthority> authorities) {this.username = username;this.password = password;this.authorities = authorities;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;} }

(4)Spring Security配置類

config包下創建SecurityConfig配置類,如下:

package com.sec.kun.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author zhoukun* @Date 2021/2/17 15:55*/ /** Spring Security配置類*/ @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/oauth/**","/login/**","/logout/**").permitAll()//放行.anyRequest().authenticated()//其他路徑攔截.and().formLogin().permitAll()//表單提交放行.and().csrf().disable();//csrf關閉}// 注冊PasswordEncoder@Beanpublic PasswordEncoder getPasswordEncoder() {return new BCryptPasswordEncoder();} }

(5)自定義登錄邏輯

service包下創建UserDetailsServiceImpl類,如下:

package com.sec.kun.service.Impl;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.AuthorityUtils; import com.sec.kun.pojo.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service;/*** @Author zhoukun* @Date 2021/2/17 15:56*/ @Service public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//實際是根據用戶名去數據庫查,這里就直接用靜態數據了if(!username.equals("86547462")) {throw new UsernameNotFoundException("用戶名不存在!");}// 密碼加密String password = passwordEncoder.encode("123456");//創建User用戶,自定義的UserUser user = new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));return user;} }

(6)認證服務配置

在config包下創建認證服務的配置類AuthorizationServerConfig,如下:

package com.sec.kun.config;/*** @Author zhoukun* @Date 2021/2/17 15:59*/import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;/*** 授權服務器*/ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()//內存中.withClient("client")//客戶端ID.secret(passwordEncoder.encode("zk2000208"))//秘鑰.redirectUris("https://www.bilibili.com")//重定向到的地址.scopes("all")//授權范圍.authorizedGrantTypes("authorization_code");//授權類型為授權碼模式} }

(7)資源服務配置

在config包下創建資源服務的配置類

/** 資源服務配置*/ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter{@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().requestMatchers().antMatchers("/user/**");}}

(8)controller

在controller包下創建UserController類,如下:

@RestController @RequestMapping("/user") public class UserController {@RequestMapping("/getCurrentUser")public Object getCurrentUser(Authentication authentication) {return authentication.getPrincipal();}}

測試

(1)獲取授權碼

啟動項目,訪問:http://localhost:8000/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
說明:
http://localhost:8000:這是項目端口。
/oauth/authorize?response_type=code:獲取授權碼的固定寫法。
client_id:這是客戶端ID,就是在授權服務中定義的:



重定向到了百度首頁,并且拿到了授權碼。
(2)獲取令牌

因為要發送post請求,所以使用postman。

url:http://localhost:8000/oauth/token

左邊的type選擇Basic Auth,右邊的用戶名為客戶端ID,密碼是定義好的。
發送請求,返回如下:

(3)獲取資源服務器資源

需要攜帶通行令牌來獲取。還是post請求:http://localhost:8000/user/getCurrentUser

Spring Security Oauth2密碼模式

環境搭建

直接在授權碼模式的基礎上進行修改了。

(1)修改SecurityConfig

直接在里面加:

//注冊AuthenticationManager@Beanpublic AuthenticationManager getAuthenticationManager() throws Exception {return super.authenticationManager();}

(2)修改AuthorizationServerConfig

直接在里面加:

/*** 密碼模式*/@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserDetailsServiceImpl userDetailsServiceImpl;//密碼模式需要配置@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception {endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsServiceImpl);}

然后下面添加密碼模式:

測試

(1)獲取Token令牌

啟動項目,直接在postman中發送:http://localhost:8000/oauth/token


(2)獲取資源

現在直接可以攜帶令牌去訪問資源:http://localhost:8000/user/getCurrentUser

Redis中存儲Token令牌

將token直接存在內存中,這在生產環境中是不合理的,下面將其改造成存儲在Redis中。

(1)pom依賴

在pom中添加如下依賴:

<!-- redis依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

(2)yml配置

在application.yml中添加:

spring:redis:host: localhostport: 6379password: 123456

在AuthorizationServerConfig加入

/*** redis工廠,默認使用lettue*/@Autowiredpublic RedisConnectionFactory redisConnectionFactory;

修改

(5)測試
啟動工程,使用密碼模式獲取令牌:

查看redis:

SpringSecurity + OAuth2.0 + JWT

前面只使用Oauth2.0的話,頒發的通行令牌長度太短了,現在想整合JWT,將頒發的token轉換一下,轉換成jwt格式的長令牌。

JWT:JSON Web Token(JWT)是一個開放的行業標準(RFC 7519),它定義了一種簡介的、自包含的協議格式,用于在通信雙方傳遞json對象,傳遞的信息經過數字簽名可以被驗證和信任。JWT可以使用HMAC算法或使用RSA的公鑰/私鑰對來簽名,防止被篡改。

整合JWT
直接在此工程的基礎上修改了。

pom

(2)Redis配置類

注釋掉Redis的配置類。
(3)Jwt配置類

在config包下創建JwtTokenStoreConfig配置類,如下:

package com.sec.kun.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;/*** @Author zhoukun* @Date 2021/2/17 19:50*/ @Configuration public class JwtTokenStoreConfig {//注冊JwtAccessTokenConverter@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();//配置jwt秘鑰jwtAccessTokenConverter.setSigningKey("zhoukun");return jwtAccessTokenConverter;}//注冊TokenStore@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(jwtAccessTokenConverter());} }

(4)修改授權配置類

修改AuthorizationServerConfig類,如下:

/***Jwt配置類*/@AutowiredJwtAccessTokenConverter jwtAccessTokenConverter;@AutowiredTokenStore tokenStore;@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception {endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsServiceImpl).tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter);}


(5)測試
使用密碼模式獲取jwt令牌,如下:

現在的access_token令牌的長度發生了變化,與它對應的是jti值。解析這個token值:

擴展JWT的內容

現在想往JWT令牌中添加自定義的內容,過程如下。

(1)Jwt內容增強器

創建一個jwt包,包下創建一個Jwt的內容增強器JwtTokenEnhancer,如下:

package com.sec.kun.hancer;import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.stereotype.Component;import java.util.HashMap; import java.util.Map;/*** @Author zhoukun* @Date 2021/2/17 19:56*/ @Component public class JwtTokenEnhancer implements TokenEnhancer {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication oAuth2Authentication) {//自定義的內容存到map中Map<String,Object> map = new HashMap<>();map.put("city","西安");map.put("like","yu");map.put("age",20);map.put("name","泡泡茶壺");//下轉型if(accessToken instanceof DefaultOAuth2AccessToken) {DefaultOAuth2AccessToken defaultOAuth2AccessToken = (DefaultOAuth2AccessToken)accessToken;defaultOAuth2AccessToken.setAdditionalInformation(map);return defaultOAuth2AccessToken;}return null;} }

(2)修改Jwt配置類

修改Jwt配置類JwtTokenStoreConfig,如下:

//密碼模式需要配置@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception {//創建TokenEnhancerChain實例TokenEnhancerChain tokenEnhancerChain=new TokenEnhancerChain();List<TokenEnhancer> enhancerList=new ArrayList<>();//配置jtv內容增強器enhancerList.add(jwtTokenEnhancer);enhancerList.add(jwtAccessTokenConverter);tokenEnhancerChain.setTokenEnhancers(enhancerList);endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsServiceImpl).tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter).tokenEnhancer(tokenEnhancerChain);}

(4)測試

解析生成的jwt令牌:

解析JWT的內容

JWT令牌的內容一般要在java程序中解析出來,以下演示過程。

(1)pom依賴

還是使用jjwt來解析。pom中添加依賴:

<!-- jjwt依賴 --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency>

(2)controller
修改UserController,如下:

@RequestMapping("/getCurrentUser")public Object getCurrentUser(Authentication authentication, HttpServletRequest request) {//獲取請求頭的指定內容String header = request.getHeader("Authorization");//截取,去掉請求頭的前6位,獲取tokenString token = header.substring(header.indexOf("bearer") + 7);//解析Token,獲取Claims對象Claims claims = Jwts.parser().setSigningKey("zhoukun".getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();return claims;}

測試
獲取令牌

帶著令牌獲取資源

獲取到了,返回的是jwt令牌解析后的內容。

JWT刷新令牌

在Spring Cloud Security中使用oauth2時,如果令牌失效了,可以使用刷新令牌通過refresh_token的授權模式再次獲取access_token,只需修改認證服務器的配置,添加refresh_token的授權模式即可。

修改授權服務配置類AuthorizationServerConfig,如下:

測試:1分鐘后再發請求:

獲取不到資源了,現在jwt通行令牌已經過期了。解決方法是加一個刷新令牌refresh_token。如下:

然后再啟動工程獲取令牌:

等1分鐘,用通行令牌獲取資源:

通行令牌過期了。現在使用刷新令牌直接從授權服務端獲取新的通行令牌:



獲取到了新的通行令牌和刷新令牌。同樣的,通行令牌的有效期還是1分鐘,刷新令牌是1小時,再用這個新的通行令牌獲取資源:

資源獲取成功。

總結

以上是生活随笔為你收集整理的Spring Security + OAuth2.0的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。