springcloud oauth2 认证服务器自定义手机短信验证码登录

springcloud 专栏收录该内容
1 篇文章 0 订阅

介绍

您已经知道,oauth2常见的授权类型authorization_code(授权码模式),password(密码模式)在spring security中都有相对于的实现,我们从AbstractTokenGranter类中可以看到一些token授予的实现。
在这里插入图片描述

自定义授权类型(短信验证码等)

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 继承抽象类AbstractTokenGranter,我们也是抽象的,后面好扩展;
 /**
 * 自定义token授予抽象实现
 */
public abstract class CustomAbstractTokenGranter extends AbstractTokenGranter {

    CustomAbstractTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
        super(tokenServices, clientDetailsService, requestFactory, grantType);
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = tokenRequest.getRequestParameters();
        UserDetails details = getUserDetails(parameters);
        if (null == details) {
            throw new InvalidGrantException("账户未找到");
        }
        Authentication userAuth = new UsernamePasswordAuthenticationToken(details.getUsername(),
                details.getPassword(), details.getAuthorities());

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, userAuth);

        /*
       	这段已经弃用了,用这种写法会出现即使你重写了getAuthorities方法,访问也没有权限403,让你产生明明给你登录的用户设置了角色或者权限,但是却访问无权限403的错觉。这种写法是没有将authorities(OAuth2Authentication的父类AbstractAuthenticationToken的属性 )的值给设置上去,authorities永远都是一个空数组。
        OAuth2Authentication authentication = super.getOAuth2Authentication(client, tokenRequest);
        authentication.setDetails(details);
        authentication.setAuthenticated(true);
        return authentication;*/
        ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191228002332851.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMzk2NjA4,size_16,color_FFFFFF,t_70)
    }

    /**
     * 自定义获取用户信息
     */
    protected abstract UserDetails getUserDetails(Map<String, String> parameters);
}
  1. 定义短信验证码具体逻辑
/**
 * 手机号-短信验证码
 */
public class PhoneSmsTokenGranter extends CustomAbstractTokenGranter {

    private static final String PHONE_SMS = "phone_sms";

    private CustomUserDetailService customUserDetailService;

    public PhoneSmsTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, CustomUserDetailService  customUserDetailService) {
        super(tokenServices, clientDetailsService, requestFactory, PHONE_SMS);
        this.customUserDetailService = customUserDetailService;
    }

    @Override
    protected UserDetails getUserDetails(Map<String, String> parameters) {
        String phone = parameters.get("phone");
        String smsCode = parameters.get("sms_code");
        return userDetailsService.loadUserByPhone(phone,smsCode);
    }
}
  1. 自定义的获取用户信息
@Service
public class CustomUserDetailService {

    UserDetails loadUserByPhone(String phone, String code) {
    	//在验证手机号和验证码
        if (!"123456".equals(code)) {
            throw new InvalidGrantException("验证码错误或已过期");
        }
        return new User(phone, "", AuthorityUtils.createAuthorityList("user:add", "user:delete"));
    }
    //按照这个思路你可以自定义二维码登录等
}
  1. 在你的授权服务器@EnableAuthorizationServerl类加入自定义的token授予

    @Autowired
    private CustomUserDetailService customUserDetailService;
 
 	/**
     * 定义授权(authorization)和令牌端点(token)以及令牌服务(token services)
     *
     * @param endpoints 配置
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        //...
        //在原有授权的基础上增加自定义手机号短信登录
        List<TokenGranter> tokenGranters = getTokenGranters(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
        //原有的授权endpoints.getTokenGranter()
        tokenGranters.add(endpoints.getTokenGranter());
        endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));
    }
    
	/**
     * 自定义TokenGranter集合
     */
    private List<TokenGranter> getTokenGranters(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        return new ArrayList<>(Collections.singletonList(
                new PhoneSmsTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailService)
        ));
    }

测试

由于我的客户端信息是在数据库的,所以得加上自定义的phone_sms类型,如果您的在内存或其他也需要给客户端加上自定义的授权类型
在这里插入图片描述
由于这个短信登录是给app端用的,这些client_id,secret是没有给app开发者的,所以app短信登录是没有直接访问默认的/oauth/token的,这里内部通过Feign请求了,并且办法的凭证进行了jwt签名(由各自需求而定)

短信验证码也在controller层进行了验证,后面的只是为了给用户颁发凭证,如果您需要在service验证,就需要把sms_code给传过去
在这里插入图片描述
在这里插入图片描述
自定义授权参考网络并在自己业务中实现

  • 1
    点赞
  • 6
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值