SpringSecurtiy OAuth2 (4) Resource Owner Password Grant - 密码模式

关于 SpringSecurity OAuth2 的 4 种模式的简要介绍性文章:
SpringSecurtiy OAuth2 (2) Authorization Code Grant - 授权码模式
SpringSecurtiy OAuth2 (3) Implicit Grant - 隐式授权模式
SpringSecurtiy OAuth2 (4) Resource Owner Password Grant - 密码模式
SpringSecurtiy OAuth2 (5) Client Credentials Grant - 客户端模式


更多细节和底层原理, 稍后会有专门的文章介绍.

关于

密码模式有一个前提就是你高度信任第三方应用. 举个不恰当的例子: 如果要在第三方应用上接入微信登录, 使用了密码模式, 那你就要在第三方应用输入微信的用户名和密码, 这肯定是不安全的, 所以密码模式需要你非常信任第三方应用.

使用场景

☼ 自己本身有一套用户体系, 在认证时需要带上自己的用户名和密码, 以及客户端的 client_id, client_secret. 此时, access-token 包含的权限是用户本身的权限, 而不是客户端的权限
可以没有前端介入 (有别于 Authorization Code GrantImplicit Grant)

整体流程

http://localhost:18907/password-authorization-server/oauth/token?grant_type=password&client_id=client-a&client_secret=client-a-p&username=caplike&password=caplike-p&scope=read_scope

授权服务器返回数据:

{
    "access_token": "aa5a459e-4da6-41a6-bf67-6b8e50c7663b",
    "token_type": "bearer",
    "expires_in": 119,
    "scope": "read_scope"
}

在这里插入图片描述

整体流程

  1. 让用户填写表单提交到授权服务器, 表单中包含用户的用户名, 密码 ,客户端的id和密钥的加密串;
  2. 授权服务器先解析并校验客户端信息, 然后校验用户信息, 完全通过返回access_token, 否则默认都是401 http状态码, 提示未授权无法访问;

实现

代码结构

├─password-authorization-server
│  │  password-authorization-server.iml
│  │  pom.xml
│  │  README.md
│  │  
│  └─src
│     └─main
│        ├─java
│        │  └─c
│        │      └─c
│        │          └─d
│        │              └─s
│        │                  └─s
│        │                      └─o
│        │                          └─p
│        │                              └─authorization
│        │                                  └─server
│        │                                      │  PasswordAuthorizationServer.java
│        │                                      │  
│        │                                      └─configuration
│        │                                              AuthorizationServerConfiguration.java
│        │                                              SecurityConfiguration.java
│        │                                              
│        └─resources
│                application.yml
│
└─password-resource-server
    │  pom.xml
    │  
    └─src
       └─main
           ├─java
           │  └─c
           │      └─c
           │          └─d
           │              └─s
           │                  └─s
           │                      └─o
           │                          └─p
           │                              └─resource
           │                                  └─server
           │                                      │  PasswordResourceServer.java
           │                                      │  
           │                                      ├─configuration
           │                                      │      ResourceServerConfiguration.java
           │                                      │      
           │                                      └─controller
           │                                              ResourceController.java
           │                                              
           └─resources
                   application.yml

授权服务器 (Authorization Server)

AuthorizationServerConfiguration

密码模式需要提供 AuthenticationManager 用户用户信息的同步验证.

@Configuration
@EnableAuthorizationServer
@Slf4j
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private PasswordEncoder passwordEncoder;

    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // @formatter:off
        clients.inMemory()

                // 客户端配置.
                // 可以是前端, 密码模式适合微服务的 Auth?
                .withClient("client-a")
                    .secret(passwordEncoder.encode("client-a-p"))
                    .resourceIds("resource-server")
                    .accessTokenValiditySeconds(60 * 12)
                    .authorizedGrantTypes("password")
                    .scopes("read_scope")

                .and()

                // 资源服务器身份配置, 用于请求授权服务器的 /oauth/check_token, 校验 access_token
                .withClient("resource-server")
                    .secret(passwordEncoder.encode("resource-server-p"))
        ;
        // @formatter:on
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        Assert.notNull(authenticationManager, "The AuthenticationManager can not be null!");
        log.info("AuthenticationManager's type: {}", authenticationManager.getClass().getCanonicalName());
        // ~ 密码模式需要 AuthenticationManager
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("isAuthenticated()");
    }

    // ~ autowired
    // -----------------------------------------------------------------------------------------------------------------

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    // ~ bean
    // -----------------------------------------------------------------------------------------------------------------

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

SecurityConfiguration

密码模式不需要前端介入, 这里可以禁用表单登陆. 同时, 提供一个 AuthenticationMnagerAuthorizationServerConfigurer

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off

        // 禁用 表单登陆
        http.formLogin().disable();

        // 禁用 Basic Auth
        http.httpBasic().disable();

        // 所有请求都需要认证
        http.authorizeRequests().anyRequest().authenticated();

        // @formatter:on
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser(User.builder().username("caplike").password(passwordEncoder.encode("caplike-p")).authorities("USER").build());
    }

    // ~ autowired
    // -----------------------------------------------------------------------------------------------------------------

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    // ~ bean
    // -----------------------------------------------------------------------------------------------------------------

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

}

资源服务器 (Resource Server)

ResourceServerConfiguration

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("resource-server").tokenServices(remoteTokenServices()).stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
    }

    /**
     * @return {@link RemoteTokenServices}
     */
    private RemoteTokenServices remoteTokenServices() {
        final RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setClientId("resource-server");
        remoteTokenServices.setClientSecret("resource-server-p");
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:18907/password-authorization-server/oauth/check_token");
        return remoteTokenServices;
    }
}

测试

在这里插入图片描述

总结

本篇简单过了一下密码模式的实现, 这种方式和前两种最大的区别就是它不需要前端介入, 用户信息和客户端信息都一次性 POST 给授权服务器. 也因为没有授权服务器接管用户登陆这一环节, 所以这种模式显得格外不安全. 适用于内部应用.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 前后端分离是一种将前端界面与后端逻辑进行分离开发的架构方式,使得前端与后端可以并行开发。OAuth 2.0是一种授权框架,用于授权和认证流程的规范化,而Spring Security是一个在Java中实现安全控制的框架,提供了大量的安全特性。Spring Authorization Server是Spring Security中用于实现授权服务器的模块,它支持OAuth 2.0的各种授权模式密码模式OAuth 2.0中的一种授权模式,它允许用户通过提交用户名和密码来获取访问令牌,然后使用该令牌来访问受保护的资源。在前后端分离的架构中,可以使用Spring Security配合Spring Authorization Server来实现密码模式的认证和授权。 在密码模式下,前端首先需要收集用户的用户名和密码,并将其发送给后端。后端使用Spring Security提供的密码编码器对密码进行加密,并验证用户名和密码的正确性。如果验证通过,则后端向客户端颁发一个访问令牌,通常是一个JWT(JSON Web Token)。前端使用获得的访问令牌来访问需要受保护的资源,每次请求将该令牌作为Authorization头的Bearer字段发送给后端进行验证。后端可以使用Spring Security的资源服务器来验证该令牌的有效性,并根据用户的权限控制对资源的访问。 使用Spring Security和Spring Authorization Server的密码模式可以实现安全的前后端分离架构。通过合理配置和使用安全特性,可以保障用户的身份认证和资源的授权,确保系统的安全性。 ### 回答2: 前后端分离是一种软件架构模式,前端和后端通过使用API进行通信,分别负责处理用户界面和数据逻辑。OAuth 2.0是一种用于授权的开放标准协议,它允许用户在第三方应用程序中授权访问其受保护的资源。Spring Security是Spring框架中的一个模块,提供了身份验证和授权功能。 在前后端分离的架构中,前端应用程序通常需要使用OAuth 2.0协议进行用户授权,以访问后端应用程序的受保护资源。为了实现密码模式,我们可以使用Spring Security的模块之一,即spring-authorization-server。 spring-authorization-server是Spring Security的一个子模块,用于实现OAuth 2.0协议中的授权服务器。密码模式OAuth 2.0协议中的一种授权模式,允许前端应用程序通过用户的用户名和密码进行授权。密码模式在安全性上有一定的风险,因此在实际应用中需要谨慎使用。 使用spring-authorization-server的密码模式,我们可以在前端应用程序中收集用户的用户名和密码,并将其提交给后端应用程序进行验证。后端应用程序将使用Spring Security进行身份验证,并向前端应用程序颁发一个访问令牌,该令牌可以用于后续的API请求。 通过使用前后端分离、OAuth 2.0和spring-authorization-server的密码模式,我们可以实现安全的用户授权和身份验证机制,确保只有经过授权的用户才能访问受保护的资源。这种架构模式能够提高系统的安全性和可扩展性,适用于各种类型的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值