授权码方式:
- 获取授权码 (浏览器直接访问)
http://localhost:8080/oauth/authorize? response_type=code& client_id=${CLIENT_ID}& redirect_uri=${callbackUrl}& scope=read
- 获取token (发送post请求,并使用basic认证,携带client_id和client_secret)
http://localhost:8080/oauth/token? grant_type=authorization_code& code=${步骤1中返回的Code}& redirect_uri=${callbackUrl}
密码模式
- 获取token(发送post请求,并使用basic认证,携带client_id和client_secret)
http://localhost:8080/oauth/token? grant_type=password& username=${USERNAME}& password=${PASSWORD}& client_id=${CLIENT_ID}& scope=read
隐式授权
- 获取token(浏览器直接访问)
http://localhost:8080/oauth/authorize? response_type=token& client_id=${CLIENT_ID}& redirect_uri=${callbackurl}& scope=read
凭证授权
- 获取token(发送post请求,并使用basic认证,携带client_id和client_secret)
http://localhost:8080/oauth/token? grant_type=client_credentials
资源服务器配置
- 配置资源服务器,添加@EnableResourceServer注释,并继承ResourceServerConfigurerAdapter进行配置
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { }
- 配置资源服务器认证时需要的AuthenticationManager对象
@Configuration @EnableWebSecurity(debug = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder() ; } // 校验token的Service @Bean public ResourceServerTokenServices tokenServices(){ RemoteTokenServices tokenServices = new RemoteTokenServices() ; tokenServices.setClientId("client_id"); tokenServices.setClientSecret("456"); tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); return tokenServices ; } // Spring security中是通过AuthenticationManager认证用户信息的 // OAuth2AuthenticationManager中使用tokenServices对用户信息进行认证 @Bean @Override protected AuthenticationManager authenticationManager() throws Exception { OAuth2AuthenticationManager auth2AuthenticationManager = new OAuth2AuthenticationManager() ; auth2AuthenticationManager.setTokenServices(tokenServices()); return auth2AuthenticationManager ; } }
- 请求被OAuth2AuthenticationProcessingFilter拦截并认证
认证服务器配置
- 配置认证服务器,添加@EnableAuthorizationServer注解,继承AuthorizationServerConfigurerAdapter并配置client
@Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { //添加客户端信息 clients.inMemory() // 使用in-memory存储客户端信息 .withClient("client_id") .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit", "client_credentials") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read","write") .secret(encoder.encode("456")) .accessTokenValiditySeconds(120)//Access token is only valid for 2 minutes. .refreshTokenValiditySeconds(600)//Refresh token is only valid for 10 minutes. .redirectUris("http://localhost:8080/callback"); } }
- 密码模式需要在认证服务器中设置 中配置AuthenticationManager
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 密码模式需要在认证服务器中设置 中配置AuthenticationManager endpoints.authenticationManager(authenticationManager); }
- 刷新令牌需要配置UserDetailService(IllegalStateException, UserDetailsService is required.)
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 刷新令牌需要用到(IllegalStateException, UserDetailsService is required.) endpoints.userDetailsService(userDetailsService) ; }
- WebSecurityConfigurerAdapter中暴露authenticationManager
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder ; @Autowired private UserDetailsService defaultUserDetailService ; // 配置AuthenticationManager的构建 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(defaultUserDetailService) .passwordEncoder(passwordEncoder); } // 密码模式需要在认证服务器中设置 中配置AuthenticationManager @Bean @Override protected AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } }
自定义rbac权限校验
- 编写rbac校验service及实现类
public interface RbacService { boolean hasPermission(HttpServletRequest request, Authentication authentication) ; } @Service("rbacService") public class RbacServiceImpl implements RbacService { private AntPathMatcher pathMatcher = new AntPathMatcher() ; @Override public boolean hasPermission(HttpServletRequest request, Authentication authentication) { String requestURI = request.getRequestURI(); log.info("request uri : {}", requestURI); //1. 获取用户权限列表 List<String> authUrlList = this.getAuthUrlList(authentication); //2. 判断用户是否用于资源地址访问权 for (String authUrl: authUrlList){ if (pathMatcher.match(authUrl, requestURI)){ return true ; } } return false; } //获取用户得权限地址列表 private List<String> getAuthUrlList(Authentication authentication){ Object principal = authentication.getPrincipal(); if (principal instanceof UserDetails){ UserDetails userDetails = (UserDetails)principal ; Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities(); return authorities.stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); } return Collections.emptyList() ; } }
- WebSecurityConfig中配置自定义权限
@Configuration @EnableWebSecurity(debug = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/hello").permitAll() .anyRequest().access("@rbacService.hasPermission(request,authentication)") ; } }
其他
- pom添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>