SpringCloud OAuth2国际化失效的问题
0
这里使用旧的OAuth2模块:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
现在需要自定义一个授权grunt_type
,实现两个组件即可AuthenticationProvider
和AbstractTokenGranter
。
白名单通过帐号直接授权Token
@Slf4j
public class MobileAuthenticationProvider implements AuthenticationProvider {
@Autowired
private WhiteIPProperties whiteIPProperties;
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final MobileToken token = (MobileToken) authentication;
final String ip = (String) token.getCredentials();
if(StringUtils.isEmpty(ip) || !this.whiteIPProperties.hasIP(ip)) {
throw MessageCodeException.of("没有权限授权IP地址:" + ip);
}
final String account = (String) token.getPrincipal();
if(StringUtils.isEmpty(account)) {
throw MessageCodeException.of("没有授权信息");
}
log.debug("移动端APP授权:{}-{}", ip, account);
final UserDetails user = this.userDetailsService.loadUserByUsername(account);
return new MobileToken(user, ip, user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return MobileToken.class.isAssignableFrom(authentication);
}
}
public class MobileTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "mobile";
private final AuthenticationManager authenticationManager;
public MobileTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
}
protected MobileTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
this.authenticationManager = authenticationManager;
}
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
final Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 验证IP
final String ip = WebUtils.clientIP(((ServletRequestAttributes) requestAttributes).getRequest());
// 验证帐号
final String account = parameters.get(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY);
// 认证信息
Authentication authentication = new MobileToken(account, ip);
((AbstractAuthenticationToken) authentication).setDetails(parameters);
try {
authentication = this.authenticationManager.authenticate(authentication);
} catch (AccountStatusException ase) {
throw new InvalidGrantException(ase.getMessage());
} catch (BadCredentialsException e) {
throw new InvalidGrantException(e.getMessage());
}
if (authentication == null || !authentication.isAuthenticated()) {
throw new InvalidGrantException("用户没有认证:" + account);
}
final OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
return new OAuth2Authentication(storedOAuth2Request, authentication);
}
}
注入
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() throws Exception {
final DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(this.passwordEncoder);
daoAuthenticationProvider.setUserDetailsService(this.userDetailsService);
daoAuthenticationProvider.afterPropertiesSet();
return daoAuthenticationProvider;
}
@Bean
public MobileAuthenticationProvider mobileAuthenticationProvider() {
return new MobileAuthenticationProvider();
}
配置
// AuthorizationServerConfigurerAdapter
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
OAuth2RequestFactory oAuth2RequestFactory = this.requestFactory;
if(oAuth2RequestFactory == null) {
oAuth2RequestFactory = new DefaultOAuth2RequestFactory(this.clientDetailsService);
}
AuthorizationCodeServices authorizationCodeServices = this.authorizationCodeServices;
if(authorizationCodeServices == null) {
authorizationCodeServices = new InMemoryAuthorizationCodeServices();
}
final AuthorizationServerTokenServices authorizationServerTokenServices = this.tokenService();
final List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
tokenGranters.add(new RefreshTokenGranter(authorizationServerTokenServices, this.clientDetailsService, oAuth2RequestFactory));
// tokenGranters.add(new ImplicitTokenGranter(authorizationServerTokenServices, this.clientDetailsService, requestFactory));
// tokenGranters.add(new ClientCredentialsTokenGranter(authorizationServerTokenServices, this.clientDetailsService, requestFactory));
tokenGranters.add(new MobileTokenGranter(this.authenticationManager, authorizationServerTokenServices, this.clientDetailsService, oAuth2RequestFactory));
tokenGranters.add(new AuthorizationCodeTokenGranter(authorizationServerTokenServices, authorizationCodeServices, this.clientDetailsService, oAuth2RequestFactory));
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(this.authenticationManager, authorizationServerTokenServices, this.clientDetailsService, oAuth2RequestFactory));
endpoints
.tokenGranter(new CompositeTokenGranter(tokenGranters))
.tokenServices(authorizationServerTokenServices)
.userDetailsService(this.userDetailsService)
.exceptionTranslator(new MessageCodeTranslator())
.authenticationManager(this.authenticationManager);
}
// WebSecurityConfigurerAdapter
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
// 一定要在这里初始:否者国际化失效
final Collection<AuthenticationProvider> values = this.context.getBeansOfType(AuthenticationProvider.class).values();
values.forEach(value -> log.info("添加登陆认证管理器:{}", value.getClass()));
final AuthenticationManager parent = super.authenticationManagerBean();
return new ProviderManager(values.stream().collect(Collectors.toList()), parent);
}
国际化失效问题
一开始我是直接注入一个ProviderManager
:
@Bean
public ProviderManager providerManager() {
final Collection<AuthenticationProvider> values = this.context.getBeansOfType(AuthenticationProvider.class).values();
values.forEach(value -> log.info("添加登陆认证管理器:{}", value.getClass()));
return new ProviderManager(values.toArray(AuthenticationProvider[]::new));
}
上面这样就会失效,需要在WebSecurityConfigurerAdapter
里面配置:
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
// 一定要在这里初始:否者国际化失效
final Collection<AuthenticationProvider> values = this.context.getBeansOfType(AuthenticationProvider.class).values();
values.forEach(value -> log.info("添加登陆认证管理器:{}", value.getClass()));
final AuthenticationManager parent = super.authenticationManagerBean();
return new ProviderManager(values.stream().collect(Collectors.toList()), parent);
}