SpringCloud OAuth2国际化失效的问题

0

这里使用旧的OAuth2模块:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

现在需要自定义一个授权grunt_type,实现两个组件即可AuthenticationProviderAbstractTokenGranter

白名单通过帐号直接授权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);
}