OAuth2.0实战(二)四种认证方式的基本使用

简介: OAuth2.0实战(二)四种认证方式的基本使用

在OAuth2.0里面有以下这几种认证方式。


authorization_code 授权码认证

client_credentials 客户端认证

password 密码认证

implicit 隐式授权认证

refresh_token 刷新密钥

一般我们会在认证请求的grant_type参数中指定采用何种方式去进行认证。比如下面的一个链接,通过grant_type=authorization_code指定采用授权码认证。

http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=client&client_secret=123456&code=jRvetc&redirect_uri=http://www.baidu.com


spring-oauth2 (bearer)是基于spring-security的验证机制,

对于第三方访问受限资源时通过token机制来验证

验证steps:

21.png


通过时序图来看一下,验证方式:

1、发送username, password, client_id, client_secret, grant_type到server

2、server返回包括access_token, token_type, refresh_token, expires_in

3、客户端向资源服务器发起请求后,资源服务器会首先拿接受的token去权限服务器验证,如果验证通过,才继续执行请求。


下面是一些默认的端点 URL:

/oauth/authorize:授权端点

/oauth/token:令牌端点

/oauth/confirm_access:用户确认授权提交端点

/oauth/error:授权服务错误信息端点

/oauth/check_token:用于资源服务访问的令牌解析端点

/oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话

授权端点的 URL 应该被 Spring Security 保护起来只供授权用户访问


下面看看具体的项目案例:


一、创建auth2_server工程



22.png

23.png


注意:名称中不能有大写字母


选择依赖:

24.png


选择创建工程的名称和保存的目录:

25.png


项目新建完成。


二、配置认证中心AuthorizationServer


核心是继承AuthorizationServerConfigurerAdapter

26.png

主要是实现三个配置方法:

1、配置认证相关属性

configure(AuthorizationServerSecurityConfigurer security)


2.配置客户端详情

configure(ClientDetailsServiceConfigurer clients)


3、配置认证服务的端点Endpoints相关属性

configure(AuthorizationServerEndpointsConfigurer endpoints)


实现如下:

在实现的AuthorizationServerConfig配置类上加上@EnableAuthorizationServer注解,说明该工程作为认证中心。

/**
 * @program: oauth2_server
 * @description: AuthorizationServer配置
 * @author: wanli
 * @create: 2019-05-22 16:00
 **/
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    // accessToken有效期
    private int accessTokenValiditySeconds = 7200; // 两小时
    private int refreshTokenValiditySeconds = 7200; // 两小时
    /**
     * 配置认证客户端ClientDetailsService
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure( ClientDetailsServiceConfigurer clients ) throws Exception {
        //这里主要配置的是客户端的信息,而不是认证用户的信息
        //添加客户端信息
        clients.inMemory()                  // 使用in-memory存储客户端信息
                .withClient("client")       // client_id
                .secret("{noop}123456")                   // client_secret
                .redirectUris("http://www.baidu.com")
                 .authorizedGrantTypes("authorization_code","password","client_credentials","refresh_token","implicit")// 该client允许的授权类型
                .scopes("app")                                   // 允许的授权范围
                .accessTokenValiditySeconds(accessTokenValiditySeconds)  //有效期时间
                .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
        ;
    }
    /**
     * 配置认证服务  oauthServer
     * @param oauthServer
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        // 允许表单认证
        oauthServer.allowFormAuthenticationForClients();
        // 允许check_token访问
        oauthServer.checkTokenAccess("permitAll()");
    }
    /**
     * 配置访问端口endpoints
     * @param endpoints
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager())
                //允许get,post方法访问 (默认获取token只能post方法)
               // .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)
        ;
    }
    @Bean
    AuthenticationManager authenticationManager() {
        AuthenticationManager authenticationManager = new AuthenticationManager() {
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                return daoAuhthenticationProvider().authenticate(authentication);
            }
        };
        return authenticationManager;
    }
    @Bean
    public AuthenticationProvider daoAuhthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService());
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        daoAuthenticationProvider.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
        return daoAuthenticationProvider;
    }
    // 设置添加用户信息,正常应该从数据库中读取
    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
        userDetailsService.createUser(User.withUsername("user1").password("{noop}123456")
                .authorities("ROLE_USER").build());
        userDetailsService.createUser(User.withUsername("user2").password("{noop}123456")
                .authorities("ROLE_USER").build());
        return userDetailsService;
    }
}


启动报错:


'authorizationEndpoint' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/servlet/ServletException


原因:

没有加入spring-boot-starter-web依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>


启动成功,默认端口8080


授权码认证 authorization_code

通过浏览器请求:

http://localhost:8080/oauth/authorize?client_id=client1&client_secret=123456&response_type=code&redirect_uri=http://www.baidu.com


出现如下异常:

User must be authenticated with Spring Security before authorization can be completed.

27.png

原因是:

进行oauth2认证前,必须先经过Spring Security的认证。


添加 Spring Security认证

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    // 拦截所有请求,使用httpBasic方式登陆
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       //拦截所有请求 通过httpBasic进行认证
        http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();  
    }
}


再次请求:

http://localhost:8080/oauth/authorize?client_id=client&client_secret=123456&response_type=code&redirect_uri=http://www.baidu.com

28.png


用户名,密码是在UserDetailsService 中配置:

user1

123456


登录成功,出现授权页面:

29.png


选择授权,重定向到百度,并在链接后面加上了授权码:

30.png

使用授权码去获取token

使用postman发起请求:

http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=client&client_secret=123456&code=jRvetc&redirect_uri=http://www.baidu.com

31.png


返回结果:

32.png


客户端认证client_credentials


post请求:

http://localhost:8080/oauth/token?grant_type=client_credentials&client_id=client&client_secret=123456

33.png

34.png



密码认证password


post请求:

http://localhost:8080/oauth/token?username=user1&password=123456&grant_type=password&client_id=client&client_secret=123456

35.png

36.png


刷新秘钥refresh_token


post请求

http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123456&refresh_token=4695c05c-de3b-4d1d-b98f-b0df204df46b

37.png


一直出现如下异常:

38.png

后台的异常信息为:

Handling error: IllegalStateException, UserDetailsService is required.


解决:

39.png

刷新秘钥refresh_token 的认证必须在AuthorizationServerEndpointsConfigurer配置中指定UserDetailsService 。不指定,对其他四种认证获取token是没有影响的。


隐式授权类型 implicit


适合直接在前端应用获取token的应用


注意:implicit和authorization_code授权请求的区别主要是

implicit的response_type=token

authorization_code的response_type = code

指定然后类型是token,请求成功后,直接将token信息链接到重定向地址后面。所以这个认证方式的安全级别相对较低。


一、get请求:

http://localhost:8080/oauth/authorize?client_id=client2&client_secret=123456&response_type=token&redirect_uri=http://www.baidu.com


二、在界面上,授权允许访问

40.png


三、根据配置的redirect_uri进行重定向,并在链接后面直接返回access_token

请求结果:

https://www.baidu.com/#access_token=d2addcfb-e29a-44ec-95c3-e4d5f2e80663&token_type=bearer&expires_in=6967&scope=app

41.png



OAuth客户端运行在浏览器中(Javascript、Flash等)

浏览器绝对可信,因为该类型可能会将访问令牌泄露给恶意用户或应用程序。

42.png

流程剖析:


其他说明:

1、如果添加spring-cloud-starter-security的依赖后,什么都不配置,默认拦截所有请求


示例,添加/hello测试方法

@SpringBootApplication
@RestController
public class Oauth2ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(Oauth2ServerApplication.class, args);
    }
    @ResponseBody
    @RequestMapping("hello")
    public  String hello(){
        return  "hello";
    }
}


请求http://localhost:8080/hello,会自动重定向到http://localhost:8080/login

43.png


默认用户是:user

密码是项目启动随机生成的。

Using generated security password: bd661305-b0bb-44d8-95ae-9655a649a5f0

44.png


2、如果在属性文件中配置security的用户属性,那么就不会生成默认用户user信息

spring.security.user.name=admin
spring.security.user.password=123456


3、在WebSecurityConfig配置类中添加默认用户

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.withUser(“user”).password("{noop}123456").roles(“USER”)
.and()
.withUser(“admin”).password("{noop}123456").roles(“USER”,“ADMIN”);
}


(1)注意密码的加密方式,这里采用的{noop},不加密

(2)只要配置了WebSecurityConfig配置类,那么认证失败重定向就会从页面,变成小弹窗

(3)在AuthorizationServerConfig和WebSecurityConfig两个配置类中,不要出现重复的配置属性,

比如,针对http是否拦截的配置,针对AuthenticationManager 的Bean的配置


github源码:

https://github.com/StarlightWANLI/oauth2.git

目录
相关文章
|
1月前
|
数据安全/隐私保护
OAuth2.0实战案例
OAuth2.0实战案例
56 0
OAuth2.0实战案例
|
4月前
|
存储 安全 API
认证服务---OAuth2.0基本介绍,微博登录测试【上篇】
这篇文章是关于OAuth2.0的介绍和微博登录测试的教程,详细解释了OAuth2.0的基本概念和授权流程,并指导读者如何在新浪微博开放平台进行应用创建、设置回调地址,以及使用Postman工具进行授权测试,为实现第三方微博登录功能做准备。
认证服务---OAuth2.0基本介绍,微博登录测试【上篇】
|
3月前
|
安全 Java 数据安全/隐私保护
|
4月前
|
缓存 安全 数据库
认证服务---OAuth2.0基本介绍,微博登录整合到实际项目中【下篇】
该博客文章介绍了如何在项目中实际应用社交登录功能,通过使用微博的OAuth 2.0授权流程来实现用户的登录和注册。
认证服务---OAuth2.0基本介绍,微博登录整合到实际项目中【下篇】
|
7月前
|
JSON 安全 API
在Python Web开发过程中:请简要介绍OAuth和JWT两种认证方式,并说明何时使用它们。
OAuth是开放授权协议,用于第三方应用安全访问用户资源;JWT是JSON格式的安全令牌,用于传递身份和权限。OAuth适合第三方登录和API访问,JWT适用于单点登录和分布式系统中的身份验证。选择取决于应用场景,两者都需确保安全实施,如加密和签名验证。
61 4
|
JSON 算法 安全
SpringBoot从入门到精通(三十四)如何集成JWT实现Token验证
近年来,随着前后端分离、微服务等架构的兴起,传统的cookie+session身份验证模式已经逐渐被基于Token的身份验证模式取代。接下来介绍如何在Spring Boot项目中集成JWT实现Token验证。
SpringBoot从入门到精通(三十四)如何集成JWT实现Token验证
|
SQL 算法 安全
一张流程图带你学会SpringBoot结合JWT实现登录功能(一)
一张流程图带你学会SpringBoot结合JWT实现登录功能
205 0
|
算法 Java 数据库
一张流程图带你学会SpringBoot结合JWT实现登录功能(二)
一张流程图带你学会SpringBoot结合JWT实现登录功能
162 0
|
存储 Java 数据库
三.SpringSecurity基础-认证原理
SpringSecurity基础-认证原理
|
存储 Java 数据库
SpringSecurity基础-认证原理
SpringSecurity是基于Filter实现认证和授权,底层通过FilterChainProxy代理去调用各种Filter(Filter链),Filter通过调用AuthenticationManager完成认证 ,通过调用AccessDecisionManager完成授权,SpringSecurity中核心的过滤器链详细如下:
106 0