接上一篇 我们已经搭建好认证微服务 下面我们开始搭建资源微服务 上一篇 假设我有一个geme_client,那么现在我们需要来搭建game-service这个微服务 现在开始创建 maven springboot工程 pom文件依赖跟上一篇依赖一样 步骤略
假设你已经搭建好上述工程(就很简单一个springboot工程所以此处略)
1.写资源服务配置
/**
* @Description auth资源配置
* @Date 2020/6/24 23:46
* @Author Jax
*/
@Configuration
@EnableResourceServer
public class OAuthResourceServiceCofig extends ResourceServerConfigurerAdapter {
/**
* 配置 resourceId 即告诉认证服务器 我就是 game-service
* @param resources
* @throws Exception
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("game-service");
}
/**
* 默认所有的请求都需要验证token
* 根据自己项目实际情况来配置
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//我这里就意思意思一下 假设配置token,test开头的url不需要验证,多个逗号隔开
.antMatchers("/token/*","/test/*")
//剩下的都需要拦截
.permitAll().anyRequest().authenticated();
}
}
2.令牌应该怎么来验证 下面来写代码
/**
* @Description 配置资源服务器Web配置
* @Date 2020/6/25 00:00
* @Author Jax
*/
@Configuration
@EnableWebSecurity
public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 声明资源服务器令牌服务
* @return
*/
@Bean
public ResourceServerTokenServices tokenServices(){
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("game_client");//认证服务器认识的client
tokenServices.setClientSecret("123456");//认证服务器认识的client secret
tokenServices.setCheckTokenEndpointUrl("http://localhost:8088/oauth/check_token");//认证服务器验证token url
return tokenServices;
}
/**
* 告诉认证服务器对应的令牌-->>用户信息
* 暴露AuthenticationManager
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
authenticationManager.setTokenServices(tokenServices());
return authenticationManager;
}
}
3.如何让自己的应用(game-service)知道我认证的这个令牌的用户信息呢(带着令牌来访问服务 我怎么知道这是哪一个用户),之前我们已经获取到token 在game-service中写一个控制器 来测试一下
@RestController
public class HelloController {
/**
* 只需要在需要用户信息的地方添加@AuthenticationPrincipal 就可以获取当前令牌的用户名了
* 目前这里只能是 String username 需要获取更复杂的用户信息 我们放第4步来实现
**/
@GetMapping("/user/test")
public String getUserMsg(@AuthenticationPrincipal String username){
System.out.println("------->>>获取到的用户用户username="+username);
return username;
}
}
向认证服务器申请令牌
使用postman访问 game-service test测试接口
查看控制台
至此 简单的资源服务器 就搭建OK了!
4.如何获取更复杂的用户信息 上面只是单纯的用户名 这样的话 我每一次 需要用户信息 都需要根据用户名去数据库查询~怎么直接从令牌里面获取复杂的用户信息呢?下面来写代码 新建一个UserDetailsServiceImpl
/**
* @Description 获取用户信息
* @Date 2020/6/25 12:31
* @Author Jax
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//TODO 根据用户名 去数据库查询当前用户对象 CurrentUser为我们自定义的返回用户对象
CurrentUser user = new CurrentUser();
user.setId(100L);
user.setUsername("abababab");
........
return user;
}
}
从上面 我们可以看到loadUserByUsername返回的是一个UserDetails 如果需要返回我们自定义的CurrentUser 我们来实现UserDetails
/**
* @Description 当前操作用户 这里我直接返回都是true 根据自己项目情况来返回下面这些方法返回的boolean 类型
* @Date 2020/6/25 14:51
* @Author Jax
*/
public class CurrentUser implements UserDetails {
//添加自己需要的用户信息字段 我这里就加一个用户id
private Long id;
private String username;
private String password;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//return null;
//方便测试 使用这个方法 把字符串转换成需要的权限集合
return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}
//账号是否过期
@Override
public boolean isAccountNonExpired() {
//TODO 应该从数据库去查询 来返回
return true;
}
//是否锁定
@Override
public boolean isAccountNonLocked() {
//TODO 应该从数据库去查询 来返回
return true;
}
//密码是否过期
@Override
public boolean isCredentialsNonExpired() {
//TODO 应该从数据库去查询 来返回
return true;
}
//账号是否可用
@Override
public boolean isEnabled() {
//TODO 应该从数据库去查询 来返回
return true;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
完成上面的代码编写 这个时候我们需要告知用我们写的UserDetailsServiceImpl来返回用户信息 在第 2 步的基础上 添加配置
/**
* @Description 配置资源服务器Web配置
* @Date 2020/6/25 00:00
* @Author Jax
*/
@Configuration
@EnableWebSecurity
public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
//注入刚刚我们自定义的UserDetailsServiceImpl
@Autowired
private UserDetailsServiceImpl userDetailsService;
/**
* 声明资源服务器令牌服务
* @return
*/
@Bean
public ResourceServerTokenServices tokenServices(){
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("game_client");//认证服务器认识的client
tokenServices.setClientSecret("123456");//认证服务器认识的client secret
tokenServices.setCheckTokenEndpointUrl("http://localhost:8088/oauth/check_token");//认证服务器验证token url
//配置返回userTokenConverter为我们自定义的UserDetails信息
tokenServices.setAccessTokenConverter(getAccessTokenConverter());
return tokenServices;
}
/**
* 告诉认证服务器对应的令牌-->>用户信息
* 暴露AuthenticationManager
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
authenticationManager.setTokenServices(tokenServices());
return authenticationManager;
}
private AccessTokenConverter getAccessTokenConverter(){
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
//默认这个UserDetailsService是null
userTokenConverter.setUserDetailsService(userDetailsService);
accessTokenConverter.setUserTokenConverter(userTokenConverter);
return accessTokenConverter;
}
}
以上步骤完成 这个时候就可以去获取我们自定义的CurrentUser 相关信息了 在第 3 步我们获取当前用户的基础上
@RestController
public class HelloController {
/**
* 默认不配置 只能获取用户名 @AuthenticationPrincipal String username
* 添加了OAuth2WebSecurityConfig中tokenServices.setAccessTokenConverter(getAccessTokenConverter());配置
* 可以直接获取当前用户 如果只想获取当前用户的id 或 其它字段的值 可以使用spring表达式来获取(可以获取这个对象的任何属性)
* 比如获取用户id @AuthenticationPrincipal(expression = "#this.id") Long userId
* @return
*/
@GetMapping("/user/test")
public String getUserMsg(@AuthenticationPrincipal CurrentUser user){
System.out.println("------->>>获取到的用户用户"+ JSON.toJSONString(user));
return "OK";
}
}
获取复杂的用户信息 配置到此结束!