当前位置:   article > 正文

SpringCloud微服务安全(三)网关安全 3-3 搭建OAuth2 认证服务器_import org.checkerframework.checker.units.qual.a;

import org.checkerframework.checker.units.qual.a;

1. OAuth2 的角色和流程

2. OAuth2 认证服务器搭建

2.1 创建认证服务器工程

(1)创建is-server-auth 认证服务器工程

(2)pom.xml 依赖

以下是使用 OAuth2 的主要依赖配置

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-security</artifactId>
  4. <version>2.2.4.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-oauth2</artifactId>
  9. <version>2.2.4.RELEASE</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-dependencies</artifactId>
  14. <version>2.3.4.RELEASE</version>
  15. <type>pom</type>
  16. <scope>import</scope>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.springframework.cloud</groupId>
  20. <artifactId>spring-cloud-dependencies</artifactId>
  21. <version>Greenwich.SR2</version>
  22. <type>pom</type>
  23. <scope>import</scope>
  24. </dependency>

2.2 创建 OAuth2AuthServerConfig.java 继承 AuthorizationServer实现自定义配置

我们需要新建一个认证服务器配置类   OAuth2AuthServerConfig继承 AuthorizationServerConfigurerAdapter ,AuthorizationServerConfigurerAdapter 是认证服务器适配器,我们看一下的源码:

  1. public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
  2. @Override
  3. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  4. }
  5. @Override
  6. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  7. }
  8. @Override
  9. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  10. }
  11. }

里面有三个方法,这三个方法,正对应上图中箭头所指的三个问题,我们需要重写这三个方法,实现自己的配置。

(1)配置Client信息    

  从图中可以看出,认证服务器要配置两个Client,一个是【客户端应用】,他需要来认证服务器申请令牌,一个是 【订单服务】,他要来认证服务器验令牌

       重写AuthorizationServerConfigurerAdapter 的   configure(ClientDetailsServiceConfigurer clients) throws Exception 方法      

  1. package com.imooc.security.server.auth;
  2. import jdk.nashorn.internal.ir.annotations.Reference;
  3. import org.checkerframework.checker.units.qual.A;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.security.authentication.AuthenticationManager;
  7. import org.springframework.security.crypto.password.PasswordEncoder;
  8. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  9. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  10. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  11. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  12. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  13. /**
  14. * @ClassName OAuth2AuthServerConfig
  15. * @Description TODO 认证服务器
  16. * @Author wushaopei
  17. * @Date 2021/5/2 21:44
  18. * @Version 1.0
  19. */
  20. @Configuration //这是一个配置类
  21. @EnableAuthorizationServer // 当前应用是一个认证服务器
  22. public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
  23. //Spring 对密码加密的封装,自己配置下
  24. @Autowired
  25. private PasswordEncoder passwordEncoder;
  26. @Autowired
  27. private AuthenticationManager authenticationManager;
  28. /***
  29. * @Description 配置客户端应用的信息,让认证服务器知道有哪些客户端应用来申请令牌。
  30. * @param clients 客户端的详情服务的配置
  31. * @throws Exception
  32. */
  33. @Override
  34. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  35. clients.inMemory() //添加客户端应用,配置在内存里,后面修改为数据库里
  36. .withClient("orderApp")// 指定client的id,应用的用户名,这里添加的是客户端应用
  37. .secret(passwordEncoder.encode("123456")) // 应用的密码
  38. .scopes("read", "write") // 应用的权限
  39. .accessTokenValiditySeconds(3600) // 令牌的有效期,单位为秒s
  40. .resourceIds("order-server") // 资源服务器的id。指:我发给orderApp的token可以访问哪些资源服务器
  41. .authorizedGrantTypes("password") // 授权方式,指可以用哪种方式去实现
  42. .and()
  43. .withClient("orderService")// 指定client的id,应用的用户名,这里添加的是订单服务。微服务中,订单服务应该具备访问其他服务的权利,同样需要获取令牌
  44. .secret(passwordEncoder.encode("12345")) // 应用的密码
  45. .scopes("read") // 应用的权限
  46. .accessTokenValiditySeconds(3600) // 令牌的有效期,单位为秒s
  47. .resourceIds("order-server") // 资源服务器的id。指:我发给orderApp的token可以访问哪些资源服务器
  48. .authorizedGrantTypes("password"); // 授权方式,指可以用哪种方式去实现
  49. }
  50. }

 (2)配置用户 信息

 告诉认证服务器,有哪些用户可以来访问认证服务器

    重写AuthorizationServerConfigurerAdapter 的   configure(AuthorizationServerEndpointsConfigurer endpoints)   方法

  1. /**
  2. * @Description TODO 配置用戶信息
  3. * @param endpoints
  4. * @throws Exception
  5. */
  6. @Override
  7. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  8. // 传给他一个authenticationManager用来校验传过来的用户信息是不是合法的,注进来一个,自己实现
  9. endpoints.authenticationManager(authenticationManager);
  10. }
  11. /**
  12. * @Description TODO 配置资源服务器过来验token的规则
  13. * @param security
  14. * @throws Exception
  15. */
  16. @Override
  17. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  18. /**
  19. * 过来验令牌有效性的请求,不是谁都能验的,必须要是经过身份认证的。
  20. * 所谓身份认证就是,必须携带clientId,clientSecret,否则随便一请求过来验token是不验的
  21. */
  22. security.checkTokenAccess("isAuthenticated()");
  23. }

上边的 加密解密类 PasswordEncoder  和  配置用户信息的 AuthenticationManager 还没有实例的来源,下边配置这俩类。

(3)新建配置类 OAuth2WebSecurityConfig 继承 WebSecurityConfigurerAdapter

  1. package com.imooc.security.server.auth;
  2. import org.checkerframework.checker.units.qual.A;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.security.authentication.AuthenticationManager;
  7. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  8. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  10. import org.springframework.security.core.userdetails.UserDetailsService;
  11. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  12. import org.springframework.security.crypto.password.PasswordEncoder;
  13. /**
  14. * @ClassName OAuth2WebSecurityConfig
  15. * @Description TODO 用于声明客户端用户的信息
  16. * @Author wushaopei
  17. * @Date 2021/5/3 10:29
  18. * @Version 1.0
  19. */
  20. @Configuration
  21. @EnableWebSecurity
  22. public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
  23. @Autowired
  24. private UserDetailsService userDetailsService;
  25. @Autowired
  26. public PasswordEncoder passwordEncoder;
  27. /**
  28. * @Description TODO AuthenticationManagerBuilder 是用来构建 AuthenticationManager(处理登录操作)的
  29. * TODO 需要两个东西:userDetailsService 、passwordEncoder
  30. * @param auth
  31. * @throws Exception
  32. */
  33. @Override
  34. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  35. auth.userDetailsService(userDetailsService)
  36. .passwordEncoder(passwordEncoder);
  37. }
  38. /**
  39. * @Description TODO 把AuthenticationManager暴露为bean
  40. * @return
  41. * @throws Exception
  42. */
  43. @Bean
  44. @Override
  45. public AuthenticationManager authenticationManagerBean() throws Exception {
  46. return super.authenticationManagerBean();
  47. }
  48. }

 passwordEncoder 本应该配置在上述类里,但是配置后报错循环依赖,暂时将其写在启动类里,不报错

(4)UserDetailsService的实现

分析:UserDetailsService接口,只有一个方法,返回UserDetails 接口:

  1. public interface UserDetailsService {
  2. UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
  3. }
loadUserByUsername,这里不用比对密码,比对密码是在AuthenticationManager里做的。UserDetails接口如下,提供了一些见名知意的方法,我们需要自定义自己的UserDetails实现类,比如你的User类实现这个接口 :
  1. public interface UserDetails extends Serializable {
  2. // ~ Methods
  3. // ========================================================================================================
  4. Collection<? extends GrantedAuthority> getAuthorities();
  5. String getPassword();
  6. String getUsername();
  7. boolean isAccountNonExpired();
  8. boolean isAccountNonLocked();
  9. boolean isCredentialsNonExpired();
  10. boolean isEnabled();
  11. }

自定义UserDetailsService 实现类:

  1. /**
  2. * @ClassName UserDetailsServiceImpl
  3. * @Description TODO
  4. * @Author wushaopei
  5. * @Date 2021/5/3 10:44
  6. * @Version 1.0
  7. */
  8. @Component
  9. @Service
  10. public class UserDetailsServiceImpl implements UserDetailsService {
  11. @Autowired
  12. private PasswordEncoder passwordEncoder;
  13. @Override
  14. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  15. return User.withUsername(username)
  16. .password(passwordEncoder.encode("123456"))
  17. .authorities("ROLE_ADMIN")
  18. .build();
  19. }
  20. }

AuthenticationManager 接口 也只有一个方法,实现类一般不需要自己实现。入参 是一个 Authentication 接口的实现,其中封装了认证的信息,不同的认证发的信息不一样,如用户名/密码 登录需要用户名密码,OAuth2则需要appId,appSecret,redirectURI等,不同的认证方式传过来的实现不同, authenticate 方法验证完了后将其中的信息更新调,返回。

  1. public interface AuthenticationManager {
  2. Authentication authenticate(Authentication authentication)
  3. throws AuthenticationException;
  4. }

2.3 获取令牌

所有的准备工作都做好了,下面启动应用,来申请一个OAuth2令牌

postman请求http://localhost:9090/oauth/token ,HttpBasic传入客户端id和客户端密码。

用图片生动解释了 OAuth2 中的角色和Spring接口 AuthorizationServerConfigurerAdapter 三个方法的关系,方便记忆

实现了OAuth2的密码模式,来申请token

存在问题:passwordEncoder 如果放在了 OAuth2WebSecurityConfig配置类里面,就会报循环依赖错误,有待解决

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/505698
推荐阅读
相关标签
  

闽ICP备14008679号