spring security oauth2 篡改登陆后的授权信息

资源服务器端通过token解析出来的授权信息的篡改

  • 通过自定义tokenService的方式去修改授权信息。
    资源服务器接收到请求后,会根据请求中带过来的access_token信息去解析出授权信息,(通过带参数access_token,获取header中添加参数Authorization,值为Bearer+token的方式),此处通过自定义tokenService,重新方法loadAuthentication来修改已授权的信息。
    具体实现方式:

  • 自定义MyTokenServices,重写方法loadAuthentication,方法如下

public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
			InvalidTokenException {
		OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
		if (accessToken == null) {
			throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
		}
		else if (accessToken.isExpired()) {
			tokenStore.removeAccessToken(accessToken);
			throw new InvalidTokenException("Access token expired: " + accessTokenValue);
		}

		OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
		try {
		   //此处为具体修改的地方,其他与源码一致
			modify(result,"authorities",AuthorityUtils.commaSeparatedStringToAuthorityList("demo2"));
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		if (result == null) {
			// in case of race condition
			throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
		}
		if (clientDetailsService != null) {
			String clientId = result.getOAuth2Request().getClientId();
			try {
				clientDetailsService.loadClientByClientId(clientId);
			}
			catch (ClientRegistrationException e) {
				throw new InvalidTokenException("Client not valid: " + clientId, e);
			}
		}
		return result;
	}


-------------------------------------------------
//通过类反射机制,修改权限信息
public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
		Field field = object.getClass().getSuperclass().getDeclaredField(fieldName);
		Field modifiersField = Field.class.getDeclaredField("modifiers");
		modifiersField.setAccessible(true); //Field 的 modifiers 是私有的
		modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
		if(!field.isAccessible()) {
			field.setAccessible(true);
		}
		field.set(object, newFieldValue);
}

客户端修改上下文中保存的授权信息

怎么在客户端中修改已从服务器端返回的信息呢,有的时候我们需要在登陆完成后,在单个客户端中自定义一些用户信息或用户权限信息,针对这个场景,需要修改服务端返回的用户授权信息。此处通过自定义过滤器的方式实现。

  1. 自定义过滤器LoginFilter
@Component
public class LoginFilter extends GenericFilterBean {

	private static final String FILTER_APPLIED = "__spring_security_customerFilter_filterApplied";

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		//防止重复调用
		if (servletRequest.getAttribute(FILTER_APPLIED) != null) {
			filterChain.doFilter(servletRequest, servletResponse);
			return;
		}
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication instanceof OAuth2Authentication) {
			OAuth2Authentication originalOAuth2Authentication = (OAuth2Authentication) authentication;
			if (!originalOAuth2Authentication.isClientOnly()) {
				Authentication userAuthentication = originalOAuth2Authentication.getUserAuthentication();
				if (userAuthentication instanceof UsernamePasswordAuthenticationToken) {
					UsernamePasswordAuthenticationToken originalUsernamePasswordAuthentication = (UsernamePasswordAuthenticationToken) userAuthentication;
					String username = (String) originalUsernamePasswordAuthentication.getPrincipal();
					// 可以根据username查找用户,这里模拟获取用户
					UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(
							originalUsernamePasswordAuthentication.getPrincipal(), "N/A",
							AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
					OAuth2Authentication oauth2Authentication = new OAuth2Authentication(
							originalOAuth2Authentication.getOAuth2Request(), usernamePasswordAuthentication);
					oauth2Authentication.setDetails(originalOAuth2Authentication.getDetails());
					SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);
				}
			}
		}
		servletRequest.setAttribute(FILTER_APPLIED, true);
		filterChain.doFilter(servletRequest, servletResponse);
	}

}
  1. 将自定义的过滤器加入过滤器链当中
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Value("${auth-server}")
	String authServer;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.addFilterAfter(getLoginFilter(), SwitchUserFilter.class)
			.anonymous().disable()
			.authorizeRequests().anyRequest().authenticated().and().csrf().disable().logout().logoutSuccessUrl(authServer+"/exit");
	}
	
	@Bean
    public LoginFilter getLoginFilter() {
    	LoginFilter filter = new LoginFilter();
        return filter;
    }
	
}

授权服务器修改授权信息

最直接的方式是将客户端设置user_info_uri,通过此方式获取用户信息,在服务器端提供一个资源/user,用来获取用户信息。推荐此种方式,只在登陆的时候调用一次服务端。

  1. 集成资源服务器
@Configuration
@EnableResourceServer
public class SsoResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
	public void configure(HttpSecurity http) throws Exception {
    	http
        .anonymous().disable().requestMatchers().antMatchers("/user")
        .and()
        .authorizeRequests().antMatchers("/user").fullyAuthenticated();
	}
}
  1. 定义/user资源,并且修改授权信息
RequestMapping("/user")
    public Principal user(Principal user) {
		Authentication authentication = (Authentication) user;
    	OAuth2Authentication originalOAuth2Authentication = (OAuth2Authentication) authentication;
    	if (!originalOAuth2Authentication.isClientOnly()) {
			Authentication userAuthentication = originalOAuth2Authentication.getUserAuthentication();
			String clientId = originalOAuth2Authentication.getOAuth2Request().getClientId();
			if (userAuthentication instanceof UsernamePasswordAuthenticationToken) {
				UsernamePasswordAuthenticationToken originalUsernamePasswordAuthentication = (UsernamePasswordAuthenticationToken) userAuthentication;
				String username = (String) originalUsernamePasswordAuthentication.getPrincipal();
				List<String> menuList = userService.getClientUserMenuList(clientId, username);
				UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(
						originalUsernamePasswordAuthentication.getPrincipal(), "N/A",
						AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.join(menuList)));
				OAuth2Authentication oauth2Authentication = new OAuth2Authentication(
						originalOAuth2Authentication.getOAuth2Request(), usernamePasswordAuthentication);
				oauth2Authentication.setDetails(originalOAuth2Authentication.getDetails());
				SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);
				return oauth2Authentication;
			}
		}
    	return authentication;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值