spring boot 2.0 整合 security oauth2 password 模式和credentials 模式

oauth2 authorization code 大致流程

  1. 用戶打開客戶端以后齿拂,客戶端要求用戶給予授權(quán)睹栖。
  2. 用戶同意給予客戶端授權(quán)敛瓷。
  3. 客戶端使用上一步獲得的授權(quán)颜懊,向認(rèn)證服務(wù)器申請令牌河哑。
  4. 認(rèn)證服務(wù)器對客戶端進(jìn)行認(rèn)證以后避诽,確認(rèn)無誤,同意發(fā)放令牌璃谨。
  5. 客戶端使用令牌沙庐,向資源服務(wù)器申請獲取資源鲤妥。
  6. 資源服務(wù)器確認(rèn)令牌無誤,同意向客戶端開放資源拱雏。

oauth2 client credentials 大致流程

  1. 客戶端獲取token
  2. 客戶端帶上token 可以任意訪問服務(wù)端的接口資源棉安,和用戶無關(guān),token中沒有用戶信息,就是處于未登陸狀態(tài)也可以訪問資源接口

oauth2 password 大致流程

  1. 客戶端帶上用戶名和密碼獲取token
  2. 獲取的token是每個用戶自己的token token中含有用戶自己的信息

security oauth2 整合的3個核心配置類

  1. 資源服務(wù)配置 ResourceServerConfiguration
  2. 授權(quán)認(rèn)證服務(wù)配置 AuthorizationServerConfiguration
  3. security 配置 SecurityConfiguration

oauth2 根據(jù)使用場景不同铸抑,分成了4種模式

  1. 授權(quán)碼模式(authorization code 即先登錄獲取code,再獲取token)
  2. 簡化模式(implicit 在redirect_uri 的Hash傳遞token; Auth客戶端運行在瀏覽器中,如JS,Flash)
  3. 密碼模式( password 將用戶名,密碼傳過去,直接獲取token)
  4. 客戶端模式(client credentials 無用戶,用戶向客戶端注冊,然后客戶端以自己的名義向’服務(wù)端’獲取資源)

demo 中使用了密碼授權(quán)模式 和客戶端授權(quán)模式

工程結(jié)構(gòu)目錄

image.png

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.0.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml

server:
  port: 18081

spring:
  application:
    name: oauth2-server   # 應(yīng)用名稱

  jpa:
      open-in-view: true
      database: POSTGRESQL
      show-sql: true
      hibernate:
        ddl-auto: update
        dialect: org.hibernate.dialect.PostgreSQLDialect
      properties:
        hibernate:
          temp:
            use_jdbc_metadata_defaults: false


  datasource:
      platform: postgres
      url: jdbc:postgresql://127.0.0.1:5432/cloud_oauth2?useUnicode=true&characterEncoding=utf-8
      username: postgres
      password: postgres123
      driver-class-name: org.postgresql.Driver

  spring:
    redis:
      host: 127.0.0.1
      database: 0

授權(quán)認(rèn)證服務(wù)配置類

@Configuration
@EnableAuthorizationServer  //  注解開啟驗證服務(wù)器 
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private static final String CLIEN_ID_ONE = "client_1";  //客戶端1 用來標(biāo)識客戶的Id
    private static final String CLIEN_ID_TWO = "client_2";  //客戶端2
    private static final String CLIEN_ID_THREE = "client_3";  //客戶端3
    private static final String CLIENT_SECRET = "secret";   //secret客戶端安全碼
    private static final String GRANT_TYPE_PASSWORD = "password";   // 密碼模式授權(quán)模式
    private static final String AUTHORIZATION_CODE = "authorization_code"; //授權(quán)碼模式  授權(quán)碼模式使用到了回調(diào)地址垂券,是最為復(fù)雜的方式,通常網(wǎng)站中經(jīng)常出現(xiàn)的微博羡滑,qq第三方登錄菇爪,都會采用這個形式。
    private static final String REFRESH_TOKEN = "refresh_token";  //
    private static final String IMPLICIT = "implicit"; //簡化授權(quán)模式
    private static final String GRANT_TYPE = "client_credentials";  //客戶端模式
    private static final String SCOPE_READ = "read";
    private static final String SCOPE_WRITE = "write";
    private static final String TRUST = "trust";
    private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60*60;          //
    private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;        //
    private static final String RESOURCE_ID = "*";    //指定哪些資源是需要授權(quán)驗證的
    
    
    @Autowired
    private AuthenticationManager authenticationManager;   //認(rèn)證方式
    @Resource(name = "userService")
    private UserDetailsService userDetailsService;


    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        String secret = new BCryptPasswordEncoder().encode(CLIENT_SECRET);  // 用 BCrypt 對密碼編碼
        //配置3個個客戶端,一個用于password認(rèn)證柒昏、一個用于client認(rèn)證凳宙、一個用于authorization_code認(rèn)證
        configurer.inMemory()  // 使用in-memory存儲
                .withClient(CLIEN_ID_ONE)    //client_id用來標(biāo)識客戶的Id  客戶端1
                .resourceIds(RESOURCE_ID)
                .authorizedGrantTypes(GRANT_TYPE, REFRESH_TOKEN)  //允許授權(quán)類型   客戶端授權(quán)模式
                .scopes(SCOPE_READ,SCOPE_WRITE)  //允許授權(quán)范圍
                .authorities("oauth2")  //客戶端可以使用的權(quán)限
                .secret(secret)  //secret客戶端安全碼
                .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)   //token 時間秒
                .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)//刷新token 時間 秒
                .and()
                .withClient(CLIEN_ID_TWO) //client_id用來標(biāo)識客戶的Id  客戶端 2
                .resourceIds(RESOURCE_ID)
                .authorizedGrantTypes(GRANT_TYPE_PASSWORD, REFRESH_TOKEN)   //允許授權(quán)類型  密碼授權(quán)模式
                .scopes(SCOPE_READ,SCOPE_WRITE) //允許授權(quán)范圍
                .authorities("oauth2") //客戶端可以使用的權(quán)限
                .secret(secret)  //secret客戶端安全碼
                .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)    //token 時間秒
                .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS); //刷新token 時間 秒

    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                .authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter())
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)  //支持GET  POST  請求獲取token
                .userDetailsService(userDetailsService) //必須注入userDetailsService否則根據(jù)refresh_token無法加載用戶信息
                .reuseRefreshTokens(true);  //開啟刷新token
    }


    /**
     * 認(rèn)證服務(wù)器的安全配置
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()") //isAuthenticated():排除anonymous   isFullyAuthenticated():排除anonymous以及remember-me
                .allowFormAuthenticationForClients();  //允許表單認(rèn)證
    }




    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("bcrypt");
        return converter;
    }


    @Bean
    public TokenStore tokenStore() {
        //基于jwt實現(xiàn)令牌(Access Token)
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public ResourceServerTokenServices tokenService() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
}    

資源服務(wù)認(rèn)證配置

@Configuration
@EnableResourceServer  
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "*";
    @Autowired
    private ResourceServerTokenServices tokenServices;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(true).tokenServices(tokenServices);
    }


    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/users/**").authenticated() //配置users訪問控制,必須認(rèn)證過后才可以訪問
                .and()
                .exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint())  //認(rèn)證失敗的業(yè)務(wù)處理
                .and()
                .logout()
                .logoutUrl("/oauth/logout")
                .logoutSuccessHandler(customLogoutSuccessHandler());   //退出成功的業(yè)務(wù)處理
    }


    @Bean
    public LogoutSuccessHandler customLogoutSuccessHandler(){
        return new CustomLogoutSuccessHandler();
    }

    @Bean
    public AuthenticationEntryPoint customAuthenticationEntryPoint(){
        return new CustomAuthenticationEntryPoint();
    }

}

Security 配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Resource(name = "userService")
    private UserDetailsService userDetailsService;

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(bCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
                .requestMatchers().anyRequest()
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());;
    }



    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

security 登錄認(rèn)證

@Service(value = "userService")<br>
public class UserServiceImpl implements UserDetailsService {

    @Autowired
    private SysAccountRepository repository;

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysAccount user = repository.findByUserAccount(username);
        if(user == null){
            throw new UsernameNotFoundException("Invalid username or password.");
        }
        return new org.springframework.security.core.userdetails.User(user.getUserAccount(), user.getUserPwd(), getAuthority());
    }

    private List getAuthority() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"));
    }

}

認(rèn)證失敗自定義處理

@Slf4j
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        log.info("      ========================================= 身份認(rèn)證失敗..................... ");

        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Access Denied");
    }
}

退出系統(tǒng)自定義處理

@Slf4j
@Component
public class CustomLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {

    @Autowired
    private TokenStore tokenStore ;

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info(" =================  成功退出系統(tǒng) .... ");
        String access_token = request.getParameter("access_token");
        if(access_token != null){
            OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(access_token);
            log.info("token =" +oAuth2AccessToken.getValue());
            tokenStore.removeAccessToken(oAuth2AccessToken);
        }
        //退出信息插入日志記錄表中
        ResultUtil.writeJavaScript(httpServletResponse,ErrorCodeEnum.SUCCESS,"退出系統(tǒng)成功."); //自己封裝的代碼 作用就是把信息返回給前端去
    }
}

測試 controller

@RestController
public class UserController {

    @GetMapping(value = "users/list")
    public String listUser(){
        return "user";
    }

    @GetMapping(value = "opt/list")
    public String optList(){
        return "optList";
    }
}

請求方式說明

1. /oauth/authorize:授權(quán)端點职祷。
2. /oauth/token:獲取token氏涩。
3. /oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點。
4. /oauth/error:授權(quán)服務(wù)錯誤信息端點有梆。
5. /oauth/check_token:用于資源服務(wù)訪問的令牌解析端點是尖。
6. /oauth/token_key:提供公有密匙的端點,如果你使用JWT令牌的話泥耀。
7. /oauth/logout: 退出

授權(quán)碼模式

  1. 瀏覽器直接訪問地址:http://localhost:18082/oauth/authorize?response_type=code&client_id=client_3&redirect_uri=http://baidu.com
      client_id:第三方應(yīng)用在授權(quán)服務(wù)器注冊的 Id

      response_type:固定值 code饺汹。

      redirect_uri:授權(quán)服務(wù)器授權(quán)重定向哪兒的 URL。

      scope:權(quán)限

      state:隨機(jī)字符串痰催,可以省略
  1. 訪問連接如果未登陸會跳轉(zhuǎn)到登陸頁面


    image.png
  2. 輸入數(shù)據(jù)庫中賬號和密碼登陸后進(jìn)行授權(quán)認(rèn)可界面


    image.png

點擊“approve” 同意授權(quán)獲取code返回:https://www.baidu.com/?code=lqByMd&state=123
點擊“deny” 拒絕授權(quán) 返回:https://www.baidu.com/?error=access_denied&error_description=User%20denied%20access&state=123

  1. 授權(quán)之后會得到一個code https://www.baidu.com/?code=123456
  2. 攜帶code獲取token
    http://localhost:18082/oauth/token?grant_type=authorization_code&code=123456&client_id=client_3&client_secret=secret&redirect_uri=http://baidu.com
    如果出現(xiàn)登陸框這輸入賬號:client_3 密碼 secret 登陸即可獲取token信息
    注意:code 只能用一次兜辞,如果失敗需要重新申請
返回:
{
   "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjE4NjM2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImQ2MjE5NDEyLTkxNDEtNDYyNi1iMjdiLWQ0M2ZhMGFkMTgzMSIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.2hsm_qXloexTLeEb1jtPOF6bIkiNYkBjg_Q2Azs9hxU",
   "token_type": "bearer",
   "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiZDYyMTk0MTItOTE0MS00NjI2LWIyN2ItZDQzZmEwYWQxODMxIiwiZXhwIjoxNTI5MjM2NjM2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImNhYWFmZTg3LWFhYzgtNDNkNC1iOTQyLTFkMDg3MDZhNjU3OSIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.Wb45Uv4aAae0AuSMttHs5XT6pJ45gGXVWUJBiWAU5UI",
   "expires_in": 3599,
   "scope": "read write",
   "jti": "d6219412-9141-4626-b27b-d43fa0ad1831"
}

客戶端模式獲取token

client模式,沒有用戶的概念夸溶,不需要傳遞username和password 參數(shù)逸吵,直接與認(rèn)證服務(wù)器交互,用配置中的客戶端信息去申請accessToken缝裁,客戶端有自己的client_id,client_secret對應(yīng)于用戶的username,password扫皱,而客戶端也擁有自己的authorities,當(dāng)采取client模式認(rèn)證時捷绑,對應(yīng)的權(quán)限也就是客戶端自己的authorities韩脑。
client模式 貌似不支持刷新token請求

請求方式:http://127.0.0.1:18081/oauth/token?grant_type=client_credentials&client_id=client_1&client_secret=secret

1. grant_type : client_credentials   client模式固定值
2. client_id : client_1 對于我們注冊客戶端的 client_id  在AuthorizationServerConfiguration配置類中
3. client_secret : secret 對于我們注冊客戶端的 secret  在AuthorizationServerConfiguration配置類中

返回:
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjI1NzgwLCJhdXRob3JpdGllcyI6WyJvYXV0aDIiXSwianRpIjoiODQ3MTgwZWMtMzM0OS00NDFiLWFlNGEtNTEwZDE3MTc5ZDY3IiwiY2xpZW50X2lkIjoiY2xpZW50XzEifQ.hVFvyYmmE6emq6G8VP8NxujeAYIiM__0Ivr4pDsbqMY",
    "token_type": "bearer",
    "expires_in": 3599,
    "scope": "read write",
    "jti": "847180ec-3349-441b-ae4a-510d17179d67"
}
image.png

image.png

密碼模式獲取token

password模式,在認(rèn)證時需要帶上自己的用戶名和密碼胎食,需要傳遞username和password 參數(shù) 扰才,以及客戶端的client_id,client_secret允懂。此時厕怜,accessToken所包含的權(quán)限是用戶本身的權(quán)限,而不是客戶端的權(quán)限。

請求方式:127.0.0.1:18081/oauth/token?username=qiaorulai&password=123456&grant_type=password&client_id=client_2&client_secret=secret

1. username : 系統(tǒng)的登錄名
2. password : 系統(tǒng)的登錄密碼
3. grant_type : password  密碼模式固定值
4. client_id : client_2 對于我們注冊客戶端的 client_id  在AuthorizationServerConfiguration配置類中
5. client_secret : secret 對于我們注冊客戶端的 secret  在AuthorizationServerConfiguration配置類中

返回:
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjE4NjM2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImQ2MjE5NDEyLTkxNDEtNDYyNi1iMjdiLWQ0M2ZhMGFkMTgzMSIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.2hsm_qXloexTLeEb1jtPOF6bIkiNYkBjg_Q2Azs9hxU",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiZDYyMTk0MTItOTE0MS00NjI2LWIyN2ItZDQzZmEwYWQxODMxIiwiZXhwIjoxNTI5MjM2NjM2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImNhYWFmZTg3LWFhYzgtNDNkNC1iOTQyLTFkMDg3MDZhNjU3OSIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.Wb45Uv4aAae0AuSMttHs5XT6pJ45gGXVWUJBiWAU5UI",
    "expires_in": 3599,
    "scope": "read write",
    "jti": "d6219412-9141-4626-b27b-d43fa0ad1831"
}
image.png
image.png

密碼模式刷新token

請求:http://localhost:18081/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiYTVkNGQyZTEtZTVhOS00MDA0LWFhNjctMjJlNzk4NGFjZTIzIiwiZXhwIjoxNTI5MjI4MDUxLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjVkNGVmMmNlLTc3MzEtNGVkYS1iZjFmLTkxZWVjYzk4YjQyOCIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.QH76vP6M3FtZt2ijNR3xWCfGGTG28adJdTrUJPztyk8&client_id=client_2&client_secret=secret

1. grant_type : password  密碼模式固定值
2. client_id : client_2 對于我們注冊客戶端的 client_id  在AuthorizationServerConfiguration配置類中
3. client_secret : secret 對于我們注冊客戶端的 secret  在AuthorizationServerConfiguration配置類中
4. refresh_token: 對應(yīng)簽名獲取token中的refresh_token值

返回:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjE4NzM5LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjAzMjc5NDM5LWNjYjYtNGI3My1iODM4LTgwNTA5YjVkNWFjNiIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.vwXCxlLRKLbqnWm6HuqAVO0j2YzSn1oHQ-GX4LZkEx8",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiMDMyNzk0MzktY2NiNi00YjczLWI4MzgtODA1MDliNWQ1YWM2IiwiZXhwIjoxNTI5MjI4MDUxLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjVkNGVmMmNlLTc3MzEtNGVkYS1iZjFmLTkxZWVjYzk4YjQyOCIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.8ihBYB99dae5MTGrWqXlJGntj4wVr8i6FNCqqAbtwdo",
    "expires_in": 3599,
    "scope": "read write",
    "jti": "03279439-ccb6-4b73-b838-80509b5d5ac6"
}
image.png
image.png

不攜帶token訪問接口

請求:127.0.0.1:18081/users/list

返回:
{
"timestamp": "2018-06-17T09:26:17.707+0000",
"status": 401,
"error": "Unauthorized",
"message": "Access Denied",
"path": "/users/list"
}

image.png

攜帶正確的token 訪問接口

請求:127.0.0.1:18081/users/list?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjMxMzE3LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6Ijc1Mzg3OWMyLTI4ZDktNDgxMy04YTAxLWZkNzQ4OGNlOWRkMCIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.V9I2lBYKk7sNsygj_bwrJZF06A8LhZx2x_MHmapppGE

返回:
正常返回數(shù)據(jù)


image.png

攜帶不正確的token 訪問接口

請求:127.0.0.1:18081/users/list?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjMxMzE3LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6Ijc1Mzg3OWMyLTI4ZDktNDgxMy04YTAxLWZkNzQ4OGNlOWRkMCIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.V9I2lBYKk7sNsygj_bwrJZF06A8LhZx2x_MHmapppGE

返回:
{
"error": "invalid_token",
"error_description": "Access token expired: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiKiJdLCJ1c2VyX25hbWUiOiJxaWFvcnVsYWkiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTI5MjE4NzM5LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjAzMjc5NDM5LWNjYjYtNGI3My1iODM4LTgwNTA5YjVkNWFjNiIsImNsaWVudF9pZCI6ImNsaWVudF8yIn0.vwXCxlLRKLbqnWm6HuqAVO0j2YzSn1oHQ-GX4LZkEx8"

image.png
image.png

demo地址:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末师抄,一起剝皮案震驚了整個濱河市亿卤,隨后出現(xiàn)的幾起案子聊品,更是在濱河造成了極大的恐慌,老刑警劉巖柄延,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缀程,居然都是意外死亡搜吧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門杨凑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滤奈,“玉大人,你說我怎么就攤上這事撩满⊙殉蹋” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵伺帘,是天一觀的道長昭躺。 經(jīng)常有香客問我,道長伪嫁,這世上最難降的妖魔是什么领炫? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮张咳,結(jié)果婚禮上驹吮,老公的妹妹穿的比我還像新娘。我一直安慰自己晶伦,他們只是感情好碟狞,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著婚陪,像睡著了一般族沃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泌参,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天脆淹,我揣著相機(jī)與錄音,去河邊找鬼沽一。 笑死盖溺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铣缠。 我是一名探鬼主播烘嘱,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼昆禽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蝇庭?” 一聲冷哼從身側(cè)響起醉鳖,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哮内,沒想到半個月后盗棵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡北发,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年纹因,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琳拨。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡辐怕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出从绘,到底是詐尸還是另有隱情寄疏,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布僵井,位于F島的核電站陕截,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏批什。R本人自食惡果不足惜农曲,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驻债。 院中可真熱鬧乳规,春花似錦、人聲如沸合呐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淌实。三九已至冻辩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拆祈,已是汗流浹背恨闪。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留放坏,地道東北人咙咽。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像淤年,于是被迫代替她去往敵國和親钧敞。 傳聞我的和親對象是個殘疾皇子蜡豹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容