SpringCloud Alibaba微服务实战三十七 - Oauth2自定义登录接口

简介: SpringCloud Alibaba微服务实战三十七 - Oauth2自定义登录接口

大家好,我是飘渺。(今天又来给大家送书了~

有不少人私下问我,为什么SpringCloud alibaba实战系列不更新了,主要是因为大部分核心功能都已经讲完了,剩下的基本是属于业务功能开发了,需要根据实际业务扩展。

今天更新文章的原因是粉丝提了个问题:如何实现Oauth2认证服务器自定义登录接口以及返回自定义格式? 这里我给大家分享一个简单且实用的方法,既可以灵活定制登录参数也可以自行组装返回结果。


实现方案


我们知道,认证服务器生成token的入口是TokenEndpoint#postAccessToken(Principal principal, @RequestParam Map<String, String> parameters),那我们就可以直接在认证服务器自定义一个登录接口,然后组装好TokenEndpoint#postAccessToken()需要的参数,直接调用它生成token后再封装成我们需要的格式即可。

接下来我们直接进入实战:

1. 定义登录参数

/**
 * 自定义登录参数
 * @author JAVA日知录
 * @date 2022/5/14 09:23
 */
@Data
public class LoginRequest {
    private String userName;
    private String password;
    private String grantType;
    private String mobile;
    private String smsCode;
}

为了兼容密码模式和自定义的短信验证码模式,我们将所有的参数都放入一个实体,大家可以根据自己的项目需要自行封装。

2. 创建一个登录类型的枚举

public enum LoginTypeEnum {
    /**
     * 密码模式
     */
    PASSWORD("password"),
    /**
     * 短信验证码模式
     */
    SMSCODE("sms_code");
    private final String grantType;
    LoginTypeEnum(String grantType) {
        this.grantType = grantType;
    }
    public String getGrantType() {
        return grantType;
    }
    public static LoginTypeEnum fromGrantType(String grantType){
        return Arrays.stream(LoginTypeEnum.values())
                .filter(item -> item.getGrantType().equals(grantType))
                .findFirst()
                .orElseThrow(()-> new BizException("不支持此登录类型"));
    }
}

3. 创建自定义登录接口(关键)

@RestController
@RequestMapping("/token")
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AuthController {
    private final TokenStore tokenStore;
    private final TokenEndpoint tokenEndpoint;
    private final RedisTemplate<String,String> redisTemplate;
    /**
     * 自定义登录接口
     * @return
     */
    @PostMapping("login")
    public ResultData<OAuth2AccessToken> login(@RequestBody LoginRequest loginRequest) throws HttpRequestMethodNotSupportedException {
        Assert.isTrue(StringUtils.isNotEmpty(loginRequest.getGrantType()), "请在参数中指定登录类型grantType");
        LoginTypeEnum typeEnum = LoginTypeEnum.fromGrantType(loginRequest.getGrantType());
        //注入clientId 和 password
        // 可以通过Header传入client 和 secret
        User clientUser = new User("jianzh5", "jianzh5", new ArrayList<>());
        Authentication token = new UsernamePasswordAuthenticationToken(clientUser, null, new ArrayList<>());
        //构建密码登录
        Map<String, String> map = new HashMap<>();
        switch (typeEnum){
            case PASSWORD : {
                map.put("username", loginRequest.getUserName());
                map.put("password", loginRequest.getPassword());
                map.put("grant_type", "password");
                break;
            }
            case SMSCODE:{
                map.put("smsCode", loginRequest.getSmsCode());
                map.put("mobile", loginRequest.getMobile());
                map.put("grant_type", "sms_code");
                break;
            }
            default: throw new BizException("不支持的登录类型");
        }
        OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(token,map).getBody();
        return ResultData.success(oAuth2AccessToken);
    }
  ...
}

这里我们将TokenEndpoint注入,然后伪装一个客户端的认证流程,调用TokenEndpoint.postAccessToken()获取接口。

这里我们写死了client信息,实际上也可以通过Header请求头传入或者通过配置文件注入。

4. 在安全配置类中放行登录接口

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  ...
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 加入验证码登陆
        http.apply(smsCodeSecurityConfig);
        http
                .authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .and()
                .authorizeRequests().antMatchers("/token/**","/sms/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf()
                .disable();
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/error",
                "/static/**",
                "/v2/api-docs/**",
                "/swagger-resources/**",
                "/webjars/**",
                "/favicon.ico"
            );
    }
}

这个安全配置类中有两个放行策略,一个通过permitAll()实现,一个通过web.ignoring()实现,他们两个的区别是:

web ignoring()比较适合配置前端相关的静态资源,它是完全绕过spring security的所有filter的;permitAll(),会给没有登录的用户适配一个AnonymousAuthenticationToken,设置到SecurityContextHolder,方便后面的filter可以统一处理authentication。

{
"userName":"zhangjian",
"password":"111111",
"grantType":"password",
"mobile":"18888887777",
"smsCode":"666666"
}


测试


1. 自定义密码登录

2. 自定义短信验证码登录

3. 不支持的登录类型


小结


本文提供的方案是将登录接口与认证服务器放在一起,如果在项目中由于某些原因不方便将其放在认证服务中,也可以让认证服务器提供一个Feign接口,然后让后端服务调用此接口进行登录即可。

好了,今天就到这儿吧,我是飘渺,我们下期见~~

目录
相关文章
|
9月前
|
算法 Java 微服务
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
微服务架构是What?? 微服务架构是一种架构模式,它提出将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。 每个服务允许在其独立的进程中,服务于服务间采用轻量级的通信机制互相协作(通常是Http协议的RESTful API或RPC协议)。 每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据上下文,选择合适的语言、工具对其进行构建
727 126
|
9月前
|
负载均衡 算法 Java
【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
1. 什么是服务治理? SpringCloud封装了Netfix开发的Eureka模块来实现服务治理 在传统pc的远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册
489 0
|
9月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
10月前
|
监控 安全 Java
Spring Cloud 微服务治理技术详解与实践指南
本文档全面介绍 Spring Cloud 微服务治理框架的核心组件、架构设计和实践应用。作为 Spring 生态系统中构建分布式系统的标准工具箱,Spring Cloud 提供了一套完整的微服务解决方案,涵盖服务发现、配置管理、负载均衡、熔断器等关键功能。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
603 1
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
943 6
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
493 1
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
2723 70
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
运维 监控 持续交付
微服务架构解析:跨越传统架构的技术革命
微服务架构(Microservices Architecture)是一种软件架构风格,它将一个大型的单体应用拆分为多个小而独立的服务,每个服务都可以独立开发、部署和扩展。
3887 37
微服务架构解析:跨越传统架构的技术革命

热门文章

最新文章