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接口,然后让后端服务调用此接口进行登录即可。

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

目录
相关文章
|
存储 JavaScript 开发工具
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
本次的.HarmonyOS Next ,ArkTS语言,HarmonyOS的元服务和DevEco Studio 开发工具,为开发者提供了构建现代化、轻量化、高性能应用的便捷方式。这些技术和工具将帮助开发者更好地适应未来的智能设备和服务提供方式。
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
|
负载均衡 Dubbo Java
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
人工智能 SpringCloudAlibaba 自然语言处理
SpringCloud Alibaba AI整合DeepSeek落地AI项目实战
在现代软件开发领域,微服务架构因其灵活性、可扩展性和模块化特性而受到广泛欢迎。微服务架构通过将大型应用程序拆分为多个小型、独立的服务,每个服务运行在其独立的进程中,服务与服务间通过轻量级通信机制(通常是HTTP API)进行通信。这种架构模式有助于提升系统的可维护性、可扩展性和开发效率。
5851 2
|
人工智能 自然语言处理 Java
Spring Cloud Alibaba AI 入门与实践
本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个在线聊天和在线画图的 AI 应用。
4502 8
|
人工智能 安全 Java
AI 时代:从 Spring Cloud Alibaba 到 Spring AI Alibaba
本次分享由阿里云智能集团云原生微服务技术负责人李艳林主讲,主题为“AI时代:从Spring Cloud Alibaba到Spring AI Alibaba”。内容涵盖应用架构演进、AI agent框架发展趋势及Spring AI Alibaba的重磅发布。分享介绍了AI原生架构与传统架构的融合,强调了API优先、事件驱动和AI运维的重要性。同时,详细解析了Spring AI Alibaba的三层抽象设计,包括模型支持、工作流智能体编排及生产可用性构建能力,确保安全合规、高效部署与可观测性。最后,结合实际案例展示了如何利用私域数据优化AI应用,提升业务价值。
1986 4
|
SpringCloudAlibaba API 开发者
新版-SpringCloud+SpringCloud Alibaba
新版-SpringCloud+SpringCloud Alibaba
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
696 1
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
16705 133
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
3558 13
Spring Cloud Alibaba:一站式微服务解决方案

热门文章

最新文章