Spring Security OAuth2.0系列之密码模式

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

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

密码模式(resource owner password credentials):密码模式中,用户向客户端提供自己的用户名和密码,这通常用在用户对客户端高度信任的情况;

1.2 授权流程图

官网图片:

Spring Security OAuth2.0系列之密码模式_第1张图片

  • (A)用户访问客户端,提供URI连接包含用户名和密码信息给授权服务器
  • (B)授权服务器对客户端进行身份验证
  • (C)授权通过,返回acceptToken给客户端

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

  • 第一步:直接传username,password获取token;

http://localhost:8080/oauth/token?password=123&grant_type=password&username=nicky&scope=all

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

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

2、例子实践

2.1 实验环境准备

  • IntelliJ IDEA
  • Maven3.+版本 新建SpringBoot Initializer项目,

pom.xml 配置:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.4
         
    
    com.allen
    spring-oauth2
    0.0.1-SNAPSHOT
    spring-oauth2
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
            org.springframework.security.oauth
            spring-security-oauth2
            2.3.3.RELEASE
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    


2.2 OAuth2.0角色

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

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

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

定义资源服务器,用注解@EnableResourceServer,主要作用是对不同URL的拦截和放行;

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

2.3 OAuth2.0配置类

新建config包,

package com.allen.springoauth2.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配置类
 * 
*/ @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(GRANT_TYPE_PASSWORD ); } @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.allen.springoauth2.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配置类
 * 
*/ @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() // 配置登出页面 .logout().logoutUrl("/logout").logoutSuccessUrl("/") // 配置允许访问的链接 .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**","/api/**").permitAll() // 其余所有请求全部需要鉴权认证 .anyRequest().authenticated() // 关闭跨域保护; .and().csrf().disable(); } }

2.5 功能简单测试

接口测试,要用POST方式,在postman测试,grant_type参数传password:

接口地址:http://localhost:8080/oauth/token

Params参数:

Spring Security OAuth2.0系列之密码模式_第2张图片

 注意配置一下请求头的授权参数,username即client_id,password即client_secret:

Spring Security OAuth2.0系列之密码模式_第3张图片

 请求结果:

Spring Security OAuth2.0系列之密码模式_第4张图片

 新建controller类,

package com.allen.springoauth2.controller;

import lombok.extern.slf4j.Slf4j;
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 :jhys
 * @date :Created in 2021/9/6 22:14
 * @Description :
 */
@RestController
@RequestMapping("/api")
@Slf4j
public class UserController {

    @GetMapping("/userinfo")
    public String getCurrentUser(Principal principal) {
        log.info("访问成功");
        return "Hello";
    }
}

拿到access_token直接去调业务接口, 访问成功!

Spring Security OAuth2.0系列之密码模式_第5张图片

你可能感兴趣的:(#,Java学习,spring,java,spring,boot)