(1)创建is-server-auth 认证服务器工程
(2)pom.xml 依赖
以下是使用 OAuth2 的主要依赖配置
2.2 创建 OAuth2AuthServerConfig.java 继承 AuthorizationServer实现自定义配置org.springframework.cloud spring-cloud-starter-security2.2.4.RELEASE org.springframework.cloud spring-cloud-starter-oauth22.2.4.RELEASE org.springframework.boot spring-boot-dependencies2.3.4.RELEASE pom import org.springframework.cloud spring-cloud-dependenciesGreenwich.SR2 pom import
我们需要新建一个认证服务器配置类 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; @Configuration //这是一个配置类 @EnableAuthorizationServer // 当前应用是一个认证服务器 public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter { //Spring 对密码加密的封装,自己配置下 @Autowired private PasswordEncoder passwordEncoder; @Autowired private AuthenticationManager authenticationManager; @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) 方法
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 传给他一个authenticationManager用来校验传过来的用户信息是不是合法的,注进来一个,自己实现 endpoints.authenticationManager(authenticationManager); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 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; @Configuration @EnableWebSecurity public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired public PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder); } @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 实现类:
@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; }2.3 获取令牌
所有的准备工作都做好了,下面启动应用,来申请一个OAuth2令牌
postman请求http://localhost:9090/oauth/token ,HttpBasic传入客户端id和客户端密码。
用图片生动解释了 OAuth2 中的角色和Spring接口 AuthorizationServerConfigurerAdapter 三个方法的关系,方便记忆
实现了OAuth2的密码模式,来申请token
存在问题:passwordEncoder 如果放在了 OAuth2WebSecurityConfig配置类里面,就会报循环依赖错误,有待解决
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)