赞
踩
(1)创建is-server-auth 认证服务器工程
(2)pom.xml 依赖
以下是使用 OAuth2 的主要依赖配置
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-security</artifactId>
- <version>2.2.4.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-oauth2</artifactId>
- <version>2.2.4.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dependencies</artifactId>
- <version>2.3.4.RELEASE</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>Greenwich.SR2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
我们需要新建一个认证服务器配置类 OAuth2AuthServerConfig ,继承 AuthorizationServerConfigurerAdapter ,AuthorizationServerConfigurerAdapter 是认证服务器适配器,我们看一下的源码:
- public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
-
- @Override
- public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
- }
-
- @Override
- public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
- }
-
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
- }
-
- }
里面有三个方法,这三个方法,正对应上图中箭头所指的三个问题,我们需要重写这三个方法,实现自己的配置。
(1)配置Client信息
从图中可以看出,认证服务器要配置两个Client,一个是【客户端应用】,他需要来认证服务器申请令牌,一个是 【订单服务】,他要来认证服务器验令牌。
重写AuthorizationServerConfigurerAdapter 的 configure(ClientDetailsServiceConfigurer clients) throws Exception 方法
- package com.imooc.security.server.auth;
-
- import jdk.nashorn.internal.ir.annotations.Reference;
- import org.checkerframework.checker.units.qual.A;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
- import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
- import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
- import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
- import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
-
- /**
- * @ClassName OAuth2AuthServerConfig
- * @Description TODO 认证服务器
- * @Author wushaopei
- * @Date 2021/5/2 21:44
- * @Version 1.0
- */
- @Configuration //这是一个配置类
- @EnableAuthorizationServer // 当前应用是一个认证服务器
- public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
- //Spring 对密码加密的封装,自己配置下
- @Autowired
- private PasswordEncoder passwordEncoder;
-
- @Autowired
- private AuthenticationManager authenticationManager;
-
- /***
- * @Description 配置客户端应用的信息,让认证服务器知道有哪些客户端应用来申请令牌。
- * @param clients 客户端的详情服务的配置
- * @throws Exception
- */
- @Override
- public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
- clients.inMemory() //添加客户端应用,配置在内存里,后面修改为数据库里
- .withClient("orderApp")// 指定client的id,应用的用户名,这里添加的是客户端应用
- .secret(passwordEncoder.encode("123456")) // 应用的密码
- .scopes("read", "write") // 应用的权限
- .accessTokenValiditySeconds(3600) // 令牌的有效期,单位为秒s
- .resourceIds("order-server") // 资源服务器的id。指:我发给orderApp的token可以访问哪些资源服务器
- .authorizedGrantTypes("password") // 授权方式,指可以用哪种方式去实现
- .and()
- .withClient("orderService")// 指定client的id,应用的用户名,这里添加的是订单服务。微服务中,订单服务应该具备访问其他服务的权利,同样需要获取令牌
- .secret(passwordEncoder.encode("12345")) // 应用的密码
- .scopes("read") // 应用的权限
- .accessTokenValiditySeconds(3600) // 令牌的有效期,单位为秒s
- .resourceIds("order-server") // 资源服务器的id。指:我发给orderApp的token可以访问哪些资源服务器
- .authorizedGrantTypes("password"); // 授权方式,指可以用哪种方式去实现
- }
- }
(2)配置用户 信息
告诉认证服务器,有哪些用户可以来访问认证服务器
重写AuthorizationServerConfigurerAdapter 的 configure(AuthorizationServerEndpointsConfigurer endpoints) 方法
- /**
- * @Description TODO 配置用戶信息
- * @param endpoints
- * @throws Exception
- */
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
- // 传给他一个authenticationManager用来校验传过来的用户信息是不是合法的,注进来一个,自己实现
- endpoints.authenticationManager(authenticationManager);
- }
-
-
- /**
- * @Description TODO 配置资源服务器过来验token的规则
- * @param security
- * @throws Exception
- */
- @Override
- public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
- /**
- * 过来验令牌有效性的请求,不是谁都能验的,必须要是经过身份认证的。
- * 所谓身份认证就是,必须携带clientId,clientSecret,否则随便一请求过来验token是不验的
- */
- security.checkTokenAccess("isAuthenticated()");
- }
上边的 加密解密类 PasswordEncoder 和 配置用户信息的 AuthenticationManager 还没有实例的来源,下边配置这俩类。
(3)新建配置类 OAuth2WebSecurityConfig 继承 WebSecurityConfigurerAdapter
- package com.imooc.security.server.auth;
-
- import org.checkerframework.checker.units.qual.A;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
- import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
- import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.security.crypto.password.PasswordEncoder;
-
- /**
- * @ClassName OAuth2WebSecurityConfig
- * @Description TODO 用于声明客户端用户的信息
- * @Author wushaopei
- * @Date 2021/5/3 10:29
- * @Version 1.0
- */
- @Configuration
- @EnableWebSecurity
- public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Autowired
- private UserDetailsService userDetailsService;
-
- @Autowired
- public PasswordEncoder passwordEncoder;
- /**
- * @Description TODO AuthenticationManagerBuilder 是用来构建 AuthenticationManager(处理登录操作)的
- * TODO 需要两个东西:userDetailsService 、passwordEncoder
- * @param auth
- * @throws Exception
- */
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(userDetailsService)
- .passwordEncoder(passwordEncoder);
- }
-
- /**
- * @Description TODO 把AuthenticationManager暴露为bean
- * @return
- * @throws Exception
- */
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
- }
passwordEncoder 本应该配置在上述类里,但是配置后报错循环依赖,暂时将其写在启动类里,不报错
(4)UserDetailsService的实现
分析:UserDetailsService接口,只有一个方法,返回UserDetails 接口:
- public interface UserDetailsService {
-
- UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
- }
loadUserByUsername,这里不用比对密码,比对密码是在AuthenticationManager里做的。UserDetails接口如下,提供了一些见名知意的方法,我们需要自定义自己的UserDetails实现类,比如你的User类实现这个接口 :
- public interface UserDetails extends Serializable {
- // ~ Methods
- // ========================================================================================================
-
- Collection<? extends GrantedAuthority> getAuthorities();
-
- String getPassword();
-
- String getUsername();
-
- boolean isAccountNonExpired();
-
- boolean isAccountNonLocked();
-
- boolean isCredentialsNonExpired();
-
- boolean isEnabled();
- }
自定义UserDetailsService 实现类:
- /**
- * @ClassName UserDetailsServiceImpl
- * @Description TODO
- * @Author wushaopei
- * @Date 2021/5/3 10:44
- * @Version 1.0
- */
- @Component
- @Service
- public class UserDetailsServiceImpl implements UserDetailsService {
-
- @Autowired
- private PasswordEncoder passwordEncoder;
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- return User.withUsername(username)
- .password(passwordEncoder.encode("123456"))
- .authorities("ROLE_ADMIN")
- .build();
- }
- }
AuthenticationManager 接口 也只有一个方法,实现类一般不需要自己实现。入参 是一个 Authentication 接口的实现,其中封装了认证的信息,不同的认证发的信息不一样,如用户名/密码 登录需要用户名密码,OAuth2则需要appId,appSecret,redirectURI等,不同的认证方式传过来的实现不同, authenticate 方法验证完了后将其中的信息更新调,返回。
- public interface AuthenticationManager {
-
- Authentication authenticate(Authentication authentication)
- throws AuthenticationException;
- }
所有的准备工作都做好了,下面启动应用,来申请一个OAuth2令牌
postman请求http://localhost:9090/oauth/token ,HttpBasic传入客户端id和客户端密码。
用图片生动解释了 OAuth2 中的角色和Spring接口 AuthorizationServerConfigurerAdapter 三个方法的关系,方便记忆
实现了OAuth2的密码模式,来申请token
存在问题:passwordEncoder 如果放在了 OAuth2WebSecurityConfig配置类里面,就会报循环依赖错误,有待解决
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。