亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

spring cloud oauth2 實現(xiàn)用戶認證登錄的示例代碼

瀏覽:3日期:2023-08-05 14:09:12

需求

在微服務(wù)架構(gòu)中,我們有很多業(yè)務(wù)模塊,每個模塊都需要有用戶認證,權(quán)限校驗。有時候也會接入來自第三方廠商的應(yīng)用。要求是只登錄一次,即可在各個服務(wù)的授權(quán)范圍內(nèi)進行操作。看到這個需求,立馬就想到了這不就是單點登錄嗎?于是基于這樣的需求,作者使用spring-cloud-oauth2去簡單的實現(xiàn)了下用戶認證和單點登錄。

相關(guān)介紹

OAuth2

OAuth2是一個關(guān)于授權(quán)的網(wǎng)絡(luò)標準,他定制了設(shè)計思路和執(zhí)行流程。OAuth2一共有四種授權(quán)模式:授權(quán)碼模式(authorization code)、簡化模式(implicit)、密碼模式(resource owner password)和客戶端模式(client credentials)。數(shù)據(jù)的所有者告訴系統(tǒng)同意授權(quán)第三方應(yīng)用進入系統(tǒng),獲取這些數(shù)據(jù)。于是數(shù)據(jù)所有者生產(chǎn)了一個短時間內(nèi)有效的授權(quán)碼(token)給第三方應(yīng)用,用來代替密碼,供第三方使用。具體流程請看下圖,具體的OAuth2介紹,可以參考這篇文章,寫的很詳細。(https://www.jb51.net/article/198292.htm)

spring cloud oauth2 實現(xiàn)用戶認證登錄的示例代碼

Token

令牌(token)和密碼(password)的作用是一樣的,都可以進入系統(tǒng)獲取資源,但是也有幾點不同:

令牌是短期的,到期會自動失效,用戶無法修改。密碼是長期的,用戶可以修改,如果不修改,就不會發(fā)生變化。 令牌可以被數(shù)據(jù)所有者撤銷,令牌會立即失效。密碼一般不允許其他人撤銷,只能被操作權(quán)限更高的人或者本人修改/重制。 令牌是有權(quán)限范圍的,會被數(shù)據(jù)所有者授予。

實現(xiàn)的功能

本篇介紹的是通過密碼模式來實現(xiàn)單點登錄的功能。

​ 在微服務(wù)架構(gòu)中,我們的一個應(yīng)用可能會有很多個服務(wù)運行,協(xié)調(diào)來處理實際的業(yè)務(wù)。這就需要用到單點登錄的技術(shù),來統(tǒng)一認證調(diào)取接口的是哪個用戶。那總不能請求一次,就認證一次,這么做肯定是不行的。那么就需要在認證完用戶之后,給這個用戶授權(quán),然后發(fā)一個令牌(token),有效期內(nèi)用戶請求資源時,就只需要帶上這個標識自己身份的token即可。

架構(gòu)說明認證中心:oauth2-oauth-server,OAuth2的服務(wù)端,主要完成用戶Token的生成、刷新、驗證等。

微服務(wù):mzh-etl,微服務(wù)之一,接收到請求之后回到認證中心(oauth2-oauth-server)去驗證。

代碼實現(xiàn)

使用到的框架是java基礎(chǔ)的spring boot 和spring-cloud-oauth2

認證中心:

1、引入需要的maven包

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>

因為spring-cloud-starter-oauth2中包含了spring-cloud-starter-security,所以就不用再單獨引入了,引入redis包是為了使用redis來存儲token。

2、配置application.yml

這里主要用到的是redis的配置,mysql數(shù)據(jù)庫的配置暫時沒有用到。

spring: application: name: oauth-server datasource: url: jdbc:mysql://localhost:3306/mzh_oauth?useSSL=false&characterEncoding=UTF-8 username: root password: admin123 driver-class-name: com.mysql.jdbc.Driver hikari: connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 maximum-pool-size: 9 redis: database: 0 host: localhost port: 6379 jedis: pool: max-active: 8 max-idle: 8 min-idle: 0 timeout: 10000server: port: 8888 use-forward-headers: truemanagement: endpoint: health: enabled: true

3、spring security 權(quán)限配置

需要繼承WebSecurityConfigurerAdapter

/** * @Author mzh * @Date 2020/10/24 */@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService customUserDetailsService; /** * 修改密碼的加密方式 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception{ return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ // 如果使用BCryptPasswordEncoder,這里就必須指定密碼的加密類 auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers('/oauth/**').permitAll(); }}

BCryptPasswordEncoder是一個不可逆的密碼加密類,AuthenticationManager是OAuth2的password必須指定的授權(quán)管理Bean。

CustomUserDetailsService這個類是被注入進來的,熟悉spring security的同學應(yīng)該知道,spring security有一個自己的UserdetailsService用于權(quán)限校驗時獲取用戶信息,但是很多時候不符合我們的業(yè)務(wù)場景,就需要重現(xiàn)實現(xiàn)這個類。

4、實現(xiàn)CustomUserDetailsService

UserDetailsService這個類的核心方法就是loadUserByUsername()方法,他接收一個用戶名,返回一個UserDetails對象。

/** * @Author mzh * @Date 2020/10/24 */@Component(value = 'customUserDetailsService')public class CustomUserDetailsService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 1. 根據(jù)username 去數(shù)據(jù)庫查詢 user // 2.獲取用戶的角色和權(quán)限 // 下面是寫死,暫時不和數(shù)據(jù)庫交互 if(!(('admin').equals(username))){ throw new UsernameNotFoundException('the user is not found'); }else{ String role = 'ADMIN_ROLE'; List<SimpleGrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority(role)); String password = passwordEncoder.encode('123456'); return new User(username,password,authorities); } }}

這里是在程序中寫死了用戶和權(quán)限。賬號:admin,密碼:123456,權(quán)限:ADMIN_ROLE(注意是權(quán)限,不是角色),實際中應(yīng)該從數(shù)據(jù)庫獲取用戶和相關(guān)的權(quán)限,然后進行認證。

5、OAuth2 配置

OAuth2配置需要繼承AuthorizationServerConfigurerAdapter類

/** * @Author mzh * @Date 2020/10/24 */@Configuration@EnableAuthorizationServerpublic class Oauth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Autowired private UserDetailsService customUserDetailsService; @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenStore redisTokenStore; /** * 對AuthorizationServerEndpointsConfigurer參數(shù)的重寫 * 重寫授權(quán)管理Bean參數(shù) * 重寫用戶校驗 * 重寫token緩存方式 * @param endpointsConfigurer * @throws Exception */ @Override public void configure(final AuthorizationServerEndpointsConfigurer endpointsConfigurer) throws Exception{ endpointsConfigurer.authenticationManager(authenticationManager) .userDetailsService(customUserDetailsService) .tokenStore(redisTokenStore); } /** * 客戶端的參數(shù)的重寫 * 這里是將數(shù)據(jù)直接寫入內(nèi)存,實際應(yīng)該從數(shù)據(jù)庫表獲取 * clientId:客戶端Id * secret:客戶端的密鑰 * authorizedGrantTypes:授權(quán)方式 * authorization_code: 授權(quán)碼類型, * implicit: 隱式授權(quán), * password: 密碼授權(quán), * client_credentials: 客戶端授權(quán), * refresh_token: 通過上面4中方式獲取的刷新令牌獲取的新令牌, * 注意是獲取token和refresh_token之后,通過refresh_toke刷新之后的令牌 * accessTokenValiditySeconds: token有效期 * scopes 用來限制客戶端訪問的權(quán)限,只有在scopes定義的范圍內(nèi),才可以正常的換取token * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception{ clients.inMemory() .and() .withClient('mzh-etl') .secret(passwordEncoder.encode('mzh-etl-8888')) .authorizedGrantTypes('refresh_token','authorization_code','password') .accessTokenValiditySeconds(3600) .scopes('all'); } @Override public void configure(AuthorizationServerSecurityConfigurer serverSecurityConfigurer) throws Exception{ serverSecurityConfigurer.allowFormAuthenticationForClients(); serverSecurityConfigurer.checkTokenAccess('permitAll()'); serverSecurityConfigurer.tokenKeyAccess('permitAll()'); serverSecurityConfigurer.passwordEncoder(passwordEncoder); }}

6、啟動服務(wù)

上述步驟完成之后啟動服務(wù),然后觀察IDEA下方的Endpoints中的Mappings,就可以找到相關(guān)的認證端口。主要的有以下幾個:

POST /oauth/authorize 授權(quán)碼模式認證授權(quán)接口 GET/POST /oauth/token 獲取 token 的接口 POST /oauth/check_token 檢查 token 合法性接口

到此,認證中心就算是創(chuàng)建完成了。我們通過idea的REST Client 來請求一個token進行測試。

請求內(nèi)容如下:

POST http://localhost:8888/oauth/token?grant_type=password&username=admin&password=123456&scope=all Accept: */* Cache-Control: no-cache Authorization: Basic dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==

第一行POST http://localhost:8888/oauth/token?grant_type=password&username=admin&password=123456&scope=all 表示發(fā)起一個POST請求,請求路徑是/oauth/token,請求參數(shù)是grant_type=password表示認證類型是password,username=admin&password=123456表示用戶名是admin,密碼是123456,scope=all是權(quán)限相關(guān)的,之前在Oauth2Config中配置了scope是all。

第四行表示在請求頭中加入一個字段Authorization,值為Basic空格base64(clientId:clientSecret),我們之前配置的clientId是“meh-etl”,clientSecret是'meh-etl-8888',所以這個值的base64是:bXpoLWV0bDptemgtZXRsLTg4ODg=。

運行請求之后,如果參數(shù)都正確的話,獲取到返回的內(nèi)容如下:

{ // token值,后面請求接口時都需要帶上的token 'access_token': 'b4cb804c-93d2-4635-913c-265ff4f37309', // token的形式 'token_type': 'bearer', // 快過期時可以用這個換取新的token 'refresh_token': '5cac05f4-158f-4561-ab16-b06c4bfe899f', // token的過期時間 'expires_in': 3599, // 權(quán)限范圍 'scope': 'all'}

token值過期之后,可以通過refresh_token來換取新的access_token

POST http://localhost:8888/oauth/token?grant_type=refresh_token&refresh_token=706dac10-d48e-4795-8379-efe8307a2282 Accept: */* Cache-Control: no-cache Authorization: Basic dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==

這次grant_type的值為“refresh_token”,refresh_token的值是要過期的token的refresh_token值,也就是之前請求獲取Token的refresh_token值,請求之后會返回一個和獲取token時一樣格式的數(shù)據(jù)。

微服務(wù)

1、引入需要的maven包

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2、配置application.yml

spring: application: name: mzh-etl redis: database: 1 host: localhost port: 6379 jedis: pool: max-active: 8 max-idle: 8 min-idle: 0 timeout: 10000server: port: 8889security: oauth2: client: # 需要和之前認證中心配置中的一樣 client-id: mzh-etl client-secret: mzh-etl-8888 # 獲取token的地址 access-token-uri: http://localhost:8888/oauth/token resource: id: mzh-etl user-info-uri: user-info authorization: # 檢查token的地址 check-token-access: http://localhost:8888/oauth/check_token

這里的配置一定要仔細,必須和之前認證中心中配置的一樣。

3、資源配置

在OAuth2中接口也稱為資源,資源的權(quán)限也就是接口的權(quán)限。spring-cloud-oauth2提供了關(guān)于資源的注解

@EnableResourceServer/** * @Author mzh * @Date 2020/10/24 */@Configuration@EnableResourceServer@EnableGlobalMethodSecurity(prePostEnabled = true)public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Value('${security.oauth2.client.client-id}') private String clientId; @Value('${security.oauth2.client.client-secret}') private String clientSecret; @Value('${security.oauth2.authorization.check-token-access}') private String checkTokenEndpointUrl; @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean('redisTokenStore') public TokenStore redisTokenStore(){ return new RedisTokenStore(redisConnectionFactory); } @Bean public RemoteTokenServices tokenService() { RemoteTokenServices tokenService = new RemoteTokenServices(); tokenService.setClientId(clientId); tokenService.setClientSecret(clientSecret); tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl); return tokenService; } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenServices(tokenService()); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers('/get/**').authenticated(); }}

4、創(chuàng)建一個接口

@RestControllerpublic class UserController { @GetMapping('get') @PreAuthorize('hasAuthority(’ADMIN_ROLE’)') public Object get(Authentication authentication){ authentication.getAuthorities(); OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails(); String token = details.getTokenValue(); return token; }}

這個接口就是會返回一個請求他時攜帶的token值,@PreAuthorize會在請求接口時檢查是否用權(quán)限“ADMIN_ROLE”(之前認證中心配置的權(quán)限)

5、啟動服務(wù)

啟動服務(wù),只有當用戶有“ADMIN_ROLE“的時候,才能正確返回,否則返回401未授權(quán)

同樣適用REST Client來發(fā)起一個請求:

GET http://localhost:8889/get Accept: */* Cache-Control: no-cache Authorization: bearer b4cb804c-93d2-4635-913c-265ff4f37309

請求路徑是http://localhost:8889/get 然后在請求頭部帶上我們上一步驟獲取到的token,放入到Authorization中,格式是bearer空格token值,如果請求成功,就會把token原樣返回。

到此這篇關(guān)于spring cloud oauth2 實現(xiàn)用戶認證登錄的示例代碼的文章就介紹到這了,更多相關(guān)spring cloud oauth2 認證登錄內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 激情啪啪网站 | 一 级 黄 色 片生活片 | 国产一级片网站 | 综合免费一区二区三区 | 131美女爽爽爽爱做视频 | 免费在线看黄色 | 国产成人永久免费视 | 99久久中文字幕伊人情人 | 美女国产福利视频 | a黄色网| 欧美一级特毛片 | 亚洲精品久一区 | 一级黄片一级毛片 | 色片免费观看 | 国产欧美日韩在线视频 | 欧美日韩一区二区三区色综合 | 成本人h片3d动漫网站在线看 | 日韩在线视频不卡 | 91蝌蚪九色 | 国产精品视频一区二区噜噜 | 韩国一级黄色大片 | 久青草国产在线视频_久青草免 | 亚洲综合日韩 | 国产亚洲精品资源一区 | 激情五月色综合色婷婷 | 欧美日韩一区二区在线视频 | 8mav福利视频在线播放 | 亚洲精品一区二区三区四区五区 | 精品亚洲一区二区三区在线播放 | 国产精品一区二区不卡的视频 | 麻豆三级视频 | 中国一级特黄真人毛片免 | 久久vs国产综合色大全 | 欧美亚洲黄色片 | 久久久久久久久女黄9999 | 99久久国产免费 - 99久久国产免费 | 正在播放淫亚洲 | 黄色a三级免费看 | 亚洲成a人片在线观看www流畅 | 久久精品国产99久久 | 国产精品免费福利 |