不废话,直接上代码,具体实现“自定义授权”如下:
1、自定义授权码模式
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 自定义授权码模式
*/
public class MyAbstractTokenGranter extends AbstractTokenGranter {
//我们授权模式注册到oauth中的名称// 这里就是授权模式名
private static final String GRANT_TYPE = "my_type";
private AuthenticationManager authenticationManager;
// 这里创建一个构造函数,配置的时候会用到
public MyAbstractTokenGranter(AuthenticationManager authenticationManager
, AuthorizationServerTokenServices tokenServices
, ClientDetailsService clientDetailsService
, OAuth2RequestFactory requestFactory) {
super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
this.authenticationManager = authenticationManager;
}
/*
* 重写方法
* @param client 客户端详细信息
* @param tokenRequest 请求参数
*
*/
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
// 这里将认证时的请求参数拿到
Map parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
//接收传入的参数
String username = parameters.get("username");authenticationManager.authenticate(userAuth);
// 这里是我们之前创建的授权前的构造函数,把参数传进去
Authentication userAuth = new MyAbstractAuthenticationToken(username); // 未认证状态
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
// 对参数进行认证
try {
userAuth = this.authenticationManager.authenticate(userAuth); // 认证中
} catch (Exception e) {
throw new InvalidGrantException(e.getMessage());
}
// 判断时候认证成功
if (userAuth == null || !userAuth.isAuthenticated()) {
throw new InvalidGrantException("Could not authenticate group company token: " + username);
}
OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
return new OAuth2Authentication(storedOAuth2Request, userAuth);
}
}
2、自定义身份授权的Token
import java.util.Collection;
/**
* 自定义身份授权令牌
*/
public class MyAbstractAuthenticationToken extends AbstractAuthenticationToken {
//我也不知道这个是干嘛用的,反正必须要有
private final Object principal;
/** 认证未通过时的初始化方法 */
public MyAbstractAuthenticationToken(String token){
super(null);
this.principal = token;
setAuthenticated(false);
}
/** 认证通过后的初始化方法 */
public MyAbstractAuthenticationToken(Object principal, Collection extends GrantedAuthority> authorities){
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
}
3、自定义身份验证
我们可以通过配置类覆盖TokenGranter,在里面注入我们自定义的授权模式!
ProviderManager#authenticate(Authentication authentication)
这个类是提供了认证的实现逻辑和流程,他负责从所有的AuthenticationProvider中找出具体的Provider进行认证
/**
* 自定义身份验证
*/
@Configuration
@RequiredArgsConstructor
public class MyAuthenticationProvider implements AuthenticationProvider {
private final UserFeignService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) {
MyAbstractAuthenticationToken myAuthenticationToken = (MyAbstractAuthenticationToken) authentication;
String userName = (String) myAuthenticationToken.getPrincipal();
UserDetails user = userDetailsService.loadUserByUsername(userName);
MyAbstractAuthenticationToken authenticationToken = new MyAbstractAuthenticationToken(userName, user.getAuthorities());
authenticationToken.setDetails(myAuthenticationToken.getDetails());
return authenticationToken;
}
@Override
public boolean supports(Class> authentication) {
return MyAbstractAuthenticationToken.class.isAssignableFrom(authentication);
}
}
4、认证服务配置中增加自定义的授权
在继承AuthorizationServerConfigurerAdapter的配置类中添加如下代码
/**
* @param endpoints
* @return
*/
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者
List granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
// 添加自定义授权模式授权者
granterList.add(new MyAbstractTokenGranter(authenticationManager, endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()
));
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
//配置存储令牌策略
endpoints
//添加自定义模式
.tokenGranter(tokenGranter(endpoints))
}
/**
* 添加自定义授权类型
*
* @return List
*/
private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
// endpoints.getTokenGranter() 获取SpringSecurity OAuth2.0 现有的授权类型
List granters = new ArrayList(Collections.singletonList(endpoints.getTokenGranter()));
// 构建自定义授权类型
MyTokenGranter smsCodeTokenGranter = new MyTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory(), myUserDetailsServiceImpl, authenticationManager);
// 向集合中添加定义授权类型
granters.add(smsCodeTokenGranter);
// 返回所有类型
return new CompositeTokenGranter(granters);
}
添加自定义的provider
在SecurityConfig中,初始化provider,代码如下:
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private IUserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//实例化provider,把需要的东西set进去
MyAuthenticationProvider provider = new MyAuthenticationProvider ();
provider.setUserDetailsService(userDetailsService);
auth.authenticationProvider(provider);
}
}