您已经知道,oauth2常见的授权类型authorization_code
(授权码模式),password
(密码模式)在spring security
中都有相对于的实现,我们从AbstractTokenGranter
类中可以看到一些token授予的实现。
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
/**
* 自定义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);
}
/**
* 手机号-短信验证码
*/
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);
}
}
@Service
public class CustomUserDetailService {
UserDetails loadByPhone(String phone, String code) {
//在验证手机号和验证码
if (!"123456".equals(code)) {
throw new InvalidGrantException("验证码错误或已过期");
}
return new User(phone, "", AuthorityUtils.createAuthorityList("user:add", "user:delete"));
}
//自定义二维码登录等
}
@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());
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给传过去
自定义授权参考网络并在自己业务中实现