List authorityList = AuthorityUtils.createAuthorityList(authSet.toArray( newString[ 0]));
returnnewSecurityUser(sysUser.getId,sysUser.getMobile,sysUser.getUsername,sysUser.getPassword,authorityList);}
3. 在ehance方法中获取当前用户并设置用户信息
publicclassCustomJwtTokenConverterextendsJwtAccessTokenConverter{@OverridepublicOAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication authentication){SecurityUser securityUser = (SecurityUser) authentication.getUserAuthentication.getPrincipal;finalMap additionalInformation = newHashMap<>( 4);additionalInformation.put( "userId", securityUser.getId);additionalInformation.put( "mobile", securityUser.getMobile);...((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(additionalInformation);returnsuper.enhance(oAuth2AccessToken,authentication);}}
如何在资源服务器中获取这些自定义信息
通过上面的配置我们可以往 jwt 的 token 中添加上用户的数据信息,但是在资源服务器中还是获取不到,通过SecurityContextHolder.getContext.getAuthentication.getPrincipal获取到的用户信息 还是只包含用户名。
这里还是得从 token 的转换器入手,默认情况下 JwtAccessTokenConverter 会调用 DefaultUserAuthenticationConverter 中的 extractAuthentication 方法从 token 中获取用户信息。
我们先看看具体实现逻辑:
publicclassDefaultUserAuthenticationConverterimplementsUserAuthenticationConverter{...publicAuthentication extractAuthentication(Map map){if( map.containsKey(USERNAME)) {Object principal = map.get(USERNAME);Collection extends GrantedAuthority> authorities = getAuthorities( map);if(userDetailsService != null) {UserDetails user = userDetailsService.loadUserByUsername((String) map.get(USERNAME));authorities = user.getAuthorities;principal = user;}returnnewUsernamePasswordAuthenticationToken(principal, "N/A", authorities);}returnnull;}...}
在没有注入 UserDetailService 的情况下,oauth2 只会获取用户名 user_name。如果注入了 UserDetailService 就可以返回所有用户信息。
所以这里我们对应的实现方式也有两种:
在资源服务器中也注入 UserDetailService ,这种方法不推荐,资源服务器与认证服务器分开的情况下强行耦合在一起,也需要加入用户认证的功能。
扩展DefaultUserAuthenticationConverter,重写extractAuthentication方法 ,手动取出额外数据,然后在资源服务器配置中将其注入到 AccessTokenConverter 中。
这里我们采用第二种方法实现,实现顺序如下:
1. 自定义 token 解析器,从 jwt token 中解析用户信息。
package com.javadaily.common.security.component;importcom.javadaily.common.security.user.SecurityUser;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.GrantedAuthority;importorg.springframework.security.core.authority.AuthorityUtils;importorg.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;importorg.springframework.util.StringUtils;
importjava.util.Collection;importjava.util.Map;
publicclassCustomUserAuthenticationConverterextendsDefaultUserAuthenticationConverter{
/*** 重写抽取用户数据方法* @author javadaily* @date 2020/11/18 10:56* @param map 用户认证信息* @return Authentication*/@ OverridepublicAuthenticationextractAuthentication( Map< String, ?> map) {if( map.containsKey( USERNAME)) {Collection extends GrantedAuthority> authorities = getAuthorities( map);Stringusername = ( String) map. get( USERNAME);Integerid = ( Integer) map. get( "userId");Stringmobile = ( String) map. get( "mobile");SecurityUseruser = new SecurityUser(id, mobile, username, "N/A", authorities);returnnew UsernamePasswordAuthenticationToken(user, "N/A", authorities);}returnnull;}
privateCollection extends GrantedAuthority> getAuthorities( Map< String, ?> map) {Objectauthorities = map. get( AUTHORITIES);if(authorities instanceof String) {returnAuthorityUtils.commaSeparatedStringToAuthorityList(( String) authorities);}if(authorities instanceof Collection) {returnAuthorityUtils.commaSeparatedStringToAuthorityList( StringUtils.collectionToCommaDelimitedString(( Collection>) authorities));}thrownew IllegalArgumentException( "Authorities must be either a String or a Collection");}
}
2. 编写自定义token转换器,注入自定义解压器
publicclassCustomAccessTokenConverterextendsDefaultAccessTokenConverter{publicCustomAccessTokenConverter{super.setUserTokenConverter( newCustomUserAuthenticationConverter);}}
3. 在资源服务器中配置类ResourceServerConfig中注入自定义token转换器
@BeanpublicJwtAccessTokenConverter jwtTokenConverter{JwtAccessTokenConverter jwtAccessTokenConverter = newJwtAccessTokenConverter;jwtAccessTokenConverter.setSigningKey( "javadaily");jwtAccessTokenConverter.setAccessTokenConverter( newCustomAccessTokenConverter);returnjwtAccessTokenConverter;}
通过上面三步配置我们再调用 SecurityContextHolder.getContext.getAuthentication.getPrincipal方法时 就可以获取到用户的额外信息了。
当然我们可以再来一个工具类,从上下文中直接获取用户信息:
@UtilityClasspublicclassSecurityUtils{/*** 获取Authentication*/publicAuthentication getAuthentication{returnSecurityContextHolder.getContext.getAuthentication;}publicSecurityUser getUser{Authentication authentication = getAuthentication;if(authentication == null) {returnnull;}returngetUser(authentication);}
/*** 获取当前用户* @paramauthentication 认证信息* @return当前用户*/privatestaticSecurityUser getUser(Authentication authentication){Object principal = authentication.getPrincipal;if(principal instanceofSecurityUser){return(SecurityUser) principal;}returnnull;}}
以上,希望对你有所帮助。返回搜狐,查看更多