OAuth2.0系列之简化模式实践教程(三)

@

目录
  • 1、简化模式简介
    • 1.1 前言简介
    • 1.2 授权流程图
  • 2、例子实践
    • 2.1 实验环境准备
    • 2.2 OAuth2.0角色
    • 2.3 OAuth2.0配置类
    • 2.4 Security配置类
    • 2.5 功能简单测试

OAuth2.0系列博客:

  • OAuth2.0系列之基本概念和运作流程(一)
  • OAuth2.0系列之授权码模式实践教程(二)
  • OAuth2.0系列之简化模式实践教程(三)
  • OAuth2.0系列之密码模式实践教程(四)
  • OAuth2.0系列之客户端模式实践教程(五)
  • OAuth2.0系列之集成JWT实现单点登录

1、简化模式简介

1.1 前言简介

在上一篇文章中我们学习了OAuth2的一些基本概念,对OAuth2有了基本的认识,接着学习OAuth2.0授权模式中的简化模式

ps:OAuth2.0的授权模式可以分为:

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此称简化模式。简化模式是相对于授权码模式而言的

1.2 授权流程图

官网图片:
OAuth2.0系列之简化模式实践教程(三)_第1张图片

http://localhost:8084/api/userinfo?access_token=${accept_token}

  • (A):客户端携带client_id、redirect_uri,中间通过代理者访问授权服务器,如果已经登录过会直接返回redirect_uri,没有登录过就跳转到登录页面
  • (B)授权服务器对客户端进行身份验证(通过用户代理,让用户输入用户名和密码)
  • (C)授权通过,会重定向到redirect_uri并携带授权码token作为uri参数
  • (D)客户端携带授权码访问资源服务器
  • (E)验证token通过,返回资源

从调接口方面,简单来说:

  • 第一步:访问授权,要传client_id:客户端id,redirect_uri:重定向uri,response_type为token,scope是授权范围,state是其它自定义参数

http://localhost:8888/oauth/authorize?client_id=cms&redirect_uri=http://localhost:8084/callback&response_type=token&scope=read&state=123

  • 第二步:授权通过,会重定向到redirect_uri,access_token码会作为它的参数

http://localhost:8084/callback#access_token=${accept_token}&token_type=bearer&state=123&expires_in=120

  • 第三步:拿到acceptToken之后,就可以直接访问资源

2、例子实践

2.1 实验环境准备

  • IntelliJ IDEA
  • Maven3.+版本
    新建SpringBoot Initializer项目,可以命名implicit
    OAuth2.0系列之简化模式实践教程(三)_第2张图片

OAuth2.0系列之简化模式实践教程(三)_第3张图片
主要是想引入:

 
            org.springframework.boot
            spring-boot-starter-web
        
 
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        
        
        
            org.springframework.cloud
            spring-cloud-starter-security
        

2.2 OAuth2.0角色

前面的学习,我们知道了OAuth2.0主要包括如下角色,下面通过代码例子加深对理论的理解

  • 资源所有者(Resource Owner)
  • 用户代理(User Agent)
  • 客户端(Client)
  • 授权服务器(Authorization Server)
  • 资源服务器(Resource Server)

生产环境、资源服务器和授权服务器一般是分开的,不过学习的可以放在一起

定义资源服务器,用注解@EnableResourceServer;
定义授权服务器,用注解@EnableAuthorizationServer;

2.3 OAuth2.0配置类

package com.example.oauth2.implicit.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;


/**
 * 
 *     OAuth2.0配置类
 * 
* *
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/06/11 11:00  修改内容:
 * 
*/ @Configuration //开启授权服务 @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; private static final String CLIENT_ID = "cms"; private static final String SECRET_CHAR_SEQUENCE = "{noop}secret"; private static final String SCOPE_READ = "read"; private static final String SCOPE_WRITE = "write"; private static final String TRUST = "trust"; private static final String USER ="user"; private static final String ALL = "all"; private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60; private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60; // 密码模式授权模式 private static final String GRANT_TYPE_PASSWORD = "password"; //授权码模式 private static final String AUTHORIZATION_CODE = "authorization_code"; //refresh token模式 private static final String REFRESH_TOKEN = "refresh_token"; //简化授权模式 private static final String IMPLICIT = "implicit"; //指定哪些资源是需要授权验证的 private static final String RESOURCE_ID = "resource_id"; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients // 使用内存存储 .inMemory() //标记客户端id .withClient(CLIENT_ID) //客户端安全码 .secret(SECRET_CHAR_SEQUENCE) //为true 直接自动授权成功返回code .autoApprove(true) .redirectUris("http://127.0.0.1:8084/cms/login") //重定向uri //允许授权范围 .scopes(ALL) //token 时间秒 .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS) //刷新token 时间 秒 .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS) //允许授权类型 .authorizedGrantTypes(IMPLICIT ); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 使用内存保存生成的token endpoints.authenticationManager(authenticationManager).tokenStore(memoryTokenStore()); } /** * 认证服务器的安全配置 * * @param security * @throws Exception */ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security //.realm(RESOURCE_ID) // 开启/oauth/token_key验证端口认证权限访问 .tokenKeyAccess("isAuthenticated()") // 开启/oauth/check_token验证端口认证权限访问 .checkTokenAccess("isAuthenticated()") //允许表单认证 .allowFormAuthenticationForClients(); } @Bean public TokenStore memoryTokenStore() { // 最基本的InMemoryTokenStore生成token return new InMemoryTokenStore(); } }

2.4 Security配置类

为了测试,可以进行简单的SpringSecurity

package com.example.oauth2.implicit.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * 
 *  SpringSecurity配置类
 * 
* *
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/06/11 11:23  修改内容:
 * 
*/ @Configuration @EnableWebSecurity @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication() auth.inMemoryAuthentication() .withUser("nicky") .password("{noop}123") .roles("admin"); } @Override public void configure(WebSecurity web) throws Exception { //解决静态资源被拦截的问题 web.ignoring().antMatchers("/asserts/**"); web.ignoring().antMatchers("/favicon.ico"); } @Override protected void configure(HttpSecurity http) throws Exception { http // 配置登录页并允许访问 .formLogin().permitAll() // 配置Basic登录 //.and().httpBasic() // 配置登出页面 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/") .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll() // 其余所有请求全部需要鉴权认证 .anyRequest().authenticated() // 关闭跨域保护; .and().csrf().disable(); } }

写个测试接口:

package com.example.oauth2.implicit.web.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

/**
 * 
 *  用户信息控制类
 * 
* *
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/06/11 14:09  修改内容:
 * 
*/ @RestController @RequestMapping("/api") public class UserController { @GetMapping("/userinfo") public Principal getCurrentUser(Principal principal) { return principal; } }

2.5 功能简单测试

访问授权链接,在浏览器访问就可以,简化模式response_type参数传token:

http://localhost:8888/oauth/authorize?client_id=cms&redirect_uri=http://127.0.0.1:8084/cms/login&response_type=token&scope=all

因为没登录,所以会返回SpringSecurity的默认登录页面,具体代码是 http .formLogin().permitAll();,如果要弹窗登录的,可以配置http.httpBasic();,这种配置是没有登录页面的,自定义登录页面可以这样配置http.formLogin().loginPage("/login").permitAll()

如图,输入SpringSecurity配置的静态账号密码:nicky/123
OAuth2.0系列之简化模式实践教程(三)_第4张图片

登录成功,返回redirect_uri,拿到token
http://127.0.0.1:8084/cms/login#access_token=9b021755-7df3-48a4-bf58-40815a4dcc9b&token_type=bearer&expires_in=119

拿到token直接去调业务接口:
http://localhost:8888/api/userinfo?access_token=9b021755-7df3-48a4-bf58-40815a4dcc9b

{
    "authorities":[
        {
            "authority":"ROLE_admin"
        }
    ],
    "details":{
        "remoteAddress":"0:0:0:0:0:0:0:1",
        "sessionId":null
    },
    "authenticated":true,
    "principal":{
        "password":null,
        "username":"nicky",
        "authorities":[
            {
                "authority":"ROLE_admin"
            }
        ],
        "accountNonExpired":true,
        "accountNonLocked":true,
        "credentialsNonExpired":true,
        "enabled":true
    },
    "credentials":null,
    "name":"nicky"
}

例子代码下载:code download

你可能感兴趣的:(OAuth2.0系列之简化模式实践教程(三))