欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2020年10月27日 10:13:51   作者:工程師小哥  
這篇文章主要介紹了spring cloud oauth2 實(shí)現(xiàn)用戶認(rèn)證登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

需求

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

相關(guān)介紹

OAuth2

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

Token

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

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

實(shí)現(xiàn)的功能

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

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

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

微服務(wù):mzh-etl,微服務(wù)之一,接收到請(qǐng)求之后回到認(rèn)證中心(oauth2-oauth-server)去驗(yàn)證。

代碼實(shí)現(xiàn)

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

認(rèn)證中心:

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>

因?yàn)閟pring-cloud-starter-oauth2中包含了spring-cloud-starter-security,所以就不用再單獨(dú)引入了,引入redis包是為了使用redis來存儲(chǔ)token。

2、配置application.yml

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

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: 10000
server:
 port: 8888
 use-forward-headers: true

management:
 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是一個(gè)不可逆的密碼加密類,AuthenticationManager是OAuth2的password必須指定的授權(quán)管理Bean。

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

4、實(shí)現(xiàn)CustomUserDetailsService

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

/**
 * @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í)不和數(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)限。賬號(hào):admin,密碼:123456,權(quán)限:ADMIN_ROLE(注意是權(quán)限,不是角色),實(shí)際中應(yīng)該從數(shù)據(jù)庫獲取用戶和相關(guān)的權(quán)限,然后進(jìn)行認(rèn)證。

5、OAuth2 配置

OAuth2配置需要繼承AuthorizationServerConfigurerAdapter類

/**
 * @Author mzh
 * @Date 2020/10/24
 */
@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {

 @Autowired
 private PasswordEncoder passwordEncoder;

 @Autowired
 private UserDetailsService customUserDetailsService;

 @Autowired
 private AuthenticationManager authenticationManager;

 @Autowired
 private TokenStore redisTokenStore;

 /**
  * 對(duì)AuthorizationServerEndpointsConfigurer參數(shù)的重寫
  * 重寫授權(quán)管理Bean參數(shù)
  * 重寫用戶校驗(yàn)
  * 重寫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)存,實(shí)際應(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、啟動(dòng)服務(wù)

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

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

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

請(qǐng)求內(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ā)起一個(gè)POST請(qǐng)求,請(qǐng)求路徑是/oauth/token,請(qǐng)求參數(shù)是grant_type=password表示認(rèn)證類型是password,username=admin&password=123456表示用戶名是admin,密碼是123456,scope=all是權(quán)限相關(guān)的,之前在Oauth2Config中配置了scope是all。

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

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

{
 // token值,后面請(qǐng)求接口時(shí)都需要帶上的token
 "access_token": "b4cb804c-93d2-4635-913c-265ff4f37309",
 // token的形式
 "token_type": "bearer",
 // 快過期時(shí)可以用這個(gè)換取新的token
 "refresh_token": "5cac05f4-158f-4561-ab16-b06c4bfe899f",
 // token的過期時(shí)間
 "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值,也就是之前請(qǐng)求獲取Token的refresh_token值,請(qǐng)求之后會(huì)返回一個(gè)和獲取token時(shí)一樣格式的數(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: 10000
server:
 port: 8889
security:
 oauth2:
 client:
  # 需要和之前認(rèn)證中心配置中的一樣
  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

這里的配置一定要仔細(xì),必須和之前認(rèn)證中心中配置的一樣。

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)建一個(gè)接口

@RestController
public 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;
 }
}

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

5、啟動(dòng)服務(wù)

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

同樣適用REST Client來發(fā)起一個(gè)請(qǐng)求:

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

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

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

相關(guān)文章

  • Java中IO流使用FileWriter寫數(shù)據(jù)基本操作詳解

    Java中IO流使用FileWriter寫數(shù)據(jù)基本操作詳解

    這篇文章主要介紹了Java中IO流FileWriter寫數(shù)據(jù)操作,FileWriter類提供了多種寫入字符的方法,包括寫入單個(gè)字符、寫入字符數(shù)組和寫入字符串等,它還提供了一些其他的方法,如刷新緩沖區(qū)、關(guān)閉文件等,需要的朋友可以參考下
    2023-10-10
  • java HashMap通過value反查key的代碼示例

    java HashMap通過value反查key的代碼示例

    本文講解了java HashMap通過value反查key的方法,直接提供代碼供大家參考使用
    2013-11-11
  • Java+Ajax實(shí)現(xiàn)的用戶名重復(fù)檢驗(yàn)功能實(shí)例詳解

    Java+Ajax實(shí)現(xiàn)的用戶名重復(fù)檢驗(yàn)功能實(shí)例詳解

    這篇文章主要介紹了Java+Ajax實(shí)現(xiàn)的用戶名重復(fù)檢驗(yàn)功能,結(jié)合實(shí)例形式詳細(xì)分析了java針對(duì)用戶名提交的ajax數(shù)據(jù)庫查詢與重復(fù)檢查功能相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2018-12-12
  • Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)賦值的方法

    Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)賦值的方法

    這篇文章主要介紹了Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)賦值的方法,涉及到通用字段自動(dòng)填充的最佳實(shí)踐總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Java不用算數(shù)運(yùn)算符來實(shí)現(xiàn)求和方法

    Java不用算數(shù)運(yùn)算符來實(shí)現(xiàn)求和方法

    我們都知道,Java的運(yùn)算符除了具有優(yōu)先級(jí)之外,還有一個(gè)結(jié)合性的特點(diǎn)。當(dāng)一個(gè)表達(dá)式中出現(xiàn)多種運(yùn)算符時(shí),執(zhí)行的先后順序不僅要遵守運(yùn)算符優(yōu)先級(jí)別的規(guī)定,還要受運(yùn)算符結(jié)合性的約束,以便確定是自左向右進(jìn)行運(yùn)算還是自右向左進(jìn)行運(yùn)算,但是如果不用運(yùn)算符怎么求和呢
    2022-04-04
  • logback.xml動(dòng)態(tài)配置程序路徑的操作

    logback.xml動(dòng)態(tài)配置程序路徑的操作

    這篇文章主要介紹了logback.xml動(dòng)態(tài)配置程序路徑的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • IDEA反編譯出整個(gè)jar包源碼

    IDEA反編譯出整個(gè)jar包源碼

    InteliJ IDEA默認(rèn)帶反編譯插件,那么如何把反編譯的jar包整體導(dǎo)出java源碼來?本文就來介紹一下,感興趣的可以了解下
    2021-05-05
  • Java中Properties的使用詳解

    Java中Properties的使用詳解

    這篇文章主要介紹了Java中Properties的使用詳解的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • SpringBoot+Netty實(shí)現(xiàn)簡(jiǎn)單聊天室的示例代碼

    SpringBoot+Netty實(shí)現(xiàn)簡(jiǎn)單聊天室的示例代碼

    這篇文章主要介紹了如何利用SpringBoot Netty實(shí)現(xiàn)簡(jiǎn)單聊天室,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)SpringBoot有一定幫助,感興趣的同學(xué)可以了解一下
    2022-02-02
  • JavaWeb?Servlet實(shí)現(xiàn)文件上傳與下載功能實(shí)例

    JavaWeb?Servlet實(shí)現(xiàn)文件上傳與下載功能實(shí)例

    因自己負(fù)責(zé)的項(xiàng)目中需要實(shí)現(xiàn)文件上傳,所以下面下面這篇文章主要給大家介紹了關(guān)于JavaWeb?Servlet實(shí)現(xiàn)文件上傳與下載功能的相關(guān)資料,需要的朋友可以參考下
    2022-04-04

最新評(píng)論