SpringCloudAlibaba+Zuul+OAuth2 (二) 搭建资源微服务

    技术2022-07-12  81

    接上一篇 我们已经搭建好认证微服务 下面我们开始搭建资源微服务 上一篇 假设我有一个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"; } }

    获取复杂的用户信息 配置到此结束!

    Processed: 0.009, SQL: 9