实现效果
使用手机号密码进行授权:
使用手机号短信验证码进行授权:
通过访问令牌获取当前用户细节:
添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
</dependencies>
创建用户细节服务
@Service
public class CustomUserDetailsService {
public UserDetails loadUserByPhoneAndPassword(String phone, String password) {
if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password)) {
throw new InvalidGrantException("无效的手机号或短信验证码");
}
// 判断成功后返回用户细节
return new User(phone, "", AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user,root"));
}
public UserDetails loadUserByPhoneAndSmsCode(String phone, String smsCode) {
if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)) {
throw new InvalidGrantException("无效的手机号或短信验证码");
}
// 判断成功后返回用户细节
return new User(phone, "", AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user,root"));
}
}
创建自定义抽象令牌授予者
public abstract class AbstractCustomTokenGranter extends AbstractTokenGranter {
private final OAuth2RequestFactory requestFactory;
protected AbstractCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
this.requestFactory = requestFactory;
}
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<String, String> parameters = tokenRequest.getRequestParameters();
CustomUser customUser = getCustomUser(parameters);
if (customUser == null) {
throw new InvalidGrantException("无法获取用户信息");
}
OAuth2Request storedOAuth2Request = this.requestFactory.createOAuth2Request(client, tokenRequest);
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(customUser, null, customUser.getAuthorities());
authentication.setDetails(customUser);
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(storedOAuth2Request, authentication);
return oAuth2Authentication;
}
protected abstract UserDetails getUserDetails(Map<String, String> parameters);
}
手机号密码登录令牌授予者
public class PhonePasswordCustomTokenGranter extends AbstractCustomTokenGranter {
private CustomUserDetailsService userDetailsService;
public PhonePasswordCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, CustomUserDetailsService userDetailsService) {
super(tokenServices, clientDetailsService, requestFactory,"custom_phone_pwd");
this.userDetailsService = userDetailsService;
}
@Override
protected UserDetails getUserDetails(Map<String, String> parameters) {
String phone = parameters.get("phone");
String password = parameters.get("password");
return userDetailsService.loadUserByPhoneAndPassword(phone, password);
}
}
短信验证码登录令牌授予者
public class PhoneSmsCustomTokenGranter extends AbstractCustomTokenGranter {
private CustomUserDetailsService userDetailsService;
public PhoneSmsCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, CustomUserDetailsService userDetailsService) {
super(tokenServices, clientDetailsService, requestFactory,"custom_phone_sms");
this.userDetailsService = userDetailsService;
}
@Override
protected UserDetails getUserDetails(Map<String, String> parameters) {
String phone = parameters.get("phone");
String smsCode = parameters.get("sms_code");
return userDetailsService.loadUserByPhoneAndSmsCode(phone, smsCode);
}
}
启用授权服务器
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
public CustomUserDetailsService customUserDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//定义一个客户端支持自定义的授权类型
clients.inMemory()
.withClient("demo")
.secret(passwordEncoder().encode("demo"))
.authorizedGrantTypes("custom_phone_pwd","custom_phone_sms")
.scopes("all");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("permitAll()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
List<TokenGranter> tokenGranters = getTokenGranters(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));
endpoints.tokenEnhancer(new TokenEnhancer() {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) oAuth2AccessToken;
CustomUser user = (CustomUser) oAuth2Authentication.getPrincipal();
Map<String, Object> map = new LinkedHashMap<>();
map.put("nickname", user.getNickname());
map.put("mobile", user.getMobile());
map.put("avatar",user.getAvatar());
token.setAdditionalInformation(map);
return oAuth2AccessToken;
}
});
}
private List<TokenGranter> getTokenGranters(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
return new ArrayList<>(Arrays.asList(
new PhoneSmsCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService),
new PhonePasswordCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService)
));
}
}
开启资源认证
@Configuration
@EnableResourceServer
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
实现获取用户细节接口
@RestController
public class AuthController {
@RequestMapping("/current-info")
public Object getUser(Authentication authentication) {
return authentication;
}
}
项目源码
https://gitee.com/yugu/demo-o...
总结
通过继承AbstractCustomTokenGranter
抽象令牌授予者类实现getUserDetails
方法获取需要的参数并调用CustomUserDetailsService
用户细节服务类的方法认证获取用户细节数据。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。