Spring Cloud Security 为构建安全的SpringBoot应用提供了一系列解决方案结合Oauth2可以实现单点登录、令牌中继、令牌交换等功能本文将对其结合Oauth2入门使用进行详细介绍。1. OAuth2 简介OAuth 2.0是用于授权的行业标准协议。OAuth 2.0为简化客户端开发提供了特定的授权流包括Web应用、桌面应用、移动端应用等。1.1. 相关名词Resource owner资源拥有者拥有该资源的最终用户他有访问资源的账号密码Resource server资源服务器拥有受保护资源的服务器如果请求包含正确的访问令牌可以访问资源Client客户端访问资源的客户端会使用访问令牌去获取资源服务器的资源可以是浏览器、移动设备或者服务器Authorization server认证服务器用于认证用户的服务器如果客户端认证通过发放访问资源服务器的令牌。1.2. 四种授权模式Authorization Code授权码模式正宗的OAuth2的授权模式客户端先将用户导向认证服务器登录后获取授权码然后进行授权最后根据授权码获取访问令牌Implicit简化模式和授权码模式相比取消了获取授权码的过程直接获取访问令牌Resource Owner Password Credentials密码模式客户端直接向用户获取用户名和密码之后向认证服务器获取访问令牌Client Credentials客户端模式客户端直接通过客户端认证比如client_id和client_secret从认证服务器获取访问令牌。其中常见的是授权码模式、密码模式授权码模式客户端将用户导向认证服务器用户在认证服务器进行登录并授权认证服务器返回授权码给客户端客户端通过授权码和跳转地址向认证服务器获取访问令牌认证服务器发放访问令牌有需要带上刷新令牌。密码模式客户端从用户获取用户名和密码客户端通过用户的用户名和密码访问认证服务器认证服务器返回访问令牌有需要带上刷新令牌。2. Oauth2的使用2.1. 构建项目并添加pom文件dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-oauth2/artifactIdversion2.2.0.RELEASE/version/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-security/artifactIdversion2.2.0.RELEASE/version/dependency2.2. 配置文件server:port:9401spring:application:name:oauth2-service2.3. 添加UserService实现UserDetailsService接口用于加载用户信息ServicepublicclassUserServiceimplementsUserDetailsService{privateListUseruserList;AutowiredprivatePasswordEncoderpasswordEncoder;PostConstructpublicvoidinitData(){StringpasswordpasswordEncoder.encode(123456);userListnewArrayList();userList.add(newUser(zhangSan,password,AuthorityUtils.commaSeparatedStringToAuthorityList(admin)));userList.add(newUser(liSi,password,AuthorityUtils.commaSeparatedStringToAuthorityList(client)));userList.add(newUser(pengyuyan,password,AuthorityUtils.commaSeparatedStringToAuthorityList(client)));}OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{ListUserfindUserListuserList.stream().filter(user-user.getUsername().equals(username)).collect(Collectors.toList());if(!CollectionUtils.isEmpty(findUserList)){returnfindUserList.get(0);}else{thrownewUsernameNotFoundException(用户名或密码错误);}}}2.4. 认证服务器配置类使用EnableAuthorizationServer注解开启ConfigurationEnableAuthorizationServerpublicclassAuthorizationServerConfigextendsAuthorizationServerConfigurerAdapter{AutowiredprivatePasswordEncoderpasswordEncoder;AutowiredprivateAuthenticationManagerauthenticationManager;AutowiredprivateUserServiceuserService;/** * 使用密码模式需要配置 */Overridepublicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints){endpoints.authenticationManager(authenticationManager).userDetailsService(userService);}Overridepublicvoidconfigure(ClientDetailsServiceConfigurerclients)throwsException{clients.inMemory().withClient(admin)//配置client_id.secret(passwordEncoder.encode(admin123456))//配置client_secret.accessTokenValiditySeconds(3600)//配置访问token的有效期.refreshTokenValiditySeconds(864000)//配置刷新token的有效期.redirectUris(http://www.baidu.com)//配置redirect_uri用于授权成功后跳转.scopes(all)//配置申请的权限范围.authorizedGrantTypes(authorization_code,password);//配置grant_type表示授权类型}}2.5. 资源服务器配置类使用EnableResourceServer注解开启ConfigurationEnableResourceServerpublicclassResourceServerConfigextendsResourceServerConfigurerAdapter{Overridepublicvoidconfigure(HttpSecurityhttp)throwsException{http.authorizeRequests().anyRequest().authenticated().and().requestMatchers().antMatchers(/user/**);//配置需要保护的资源路径}}2.6. SpringSecurity配置类允许认证相关路径的访问及表单登录ConfigurationEnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}BeanOverridepublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}Overridepublicvoidconfigure(HttpSecurityhttp)throwsException{http.csrf().disable().authorizeRequests().antMatchers(/oauth/**,/login/**,/logout/**).permitAll().anyRequest().authenticated().and().formLogin().permitAll();}}2.7. 创建登录接口用于测试RestControllerRequestMapping(/user)publicclassUserController{GetMapping(/getCurrentUser)publicObjectgetCurrentUser(Authenticationauthentication){returnauthentication.getPrincipal();}}2.8. 登录2.8.1. 授权码模式使用启动服务在浏览器访问http://localhost:9401/oauth/authorize?response_typecodeclient_idadminredirect_urihttp://www.baidu.comscopeallstatenormal进行登录授权输入账号密码进行登录操作登录后进行授权操作之后浏览器会带着授权码重定向到百度https://www.baidu.com/?codeCKBS20statenormal使用授权码请求http://localhost:9401/oauth/token获取访问令牌使用Basic认证通过client_id和client_secretAuthorizationServerConfig类中做了默认配置构造一个Authorization头信息在body中添加以下参数信息通过POST请求获取访问令牌在下图接口请求头中添加访问令牌发现已经可以成功访问。2.8.2. 密码模式使用使用密码请求http://localhost:9401/oauth/token获取访问令牌使用Basic认证通过client_id和client_secret构造一个Authorization头信息略在body中添加以下参数信息通过POST请求获取访问令牌再次在getCurrentUser接口请求头中添加访问令牌发现已经可以成功访问。