# 28\. Security 如果Spring Security位于类路径上,则默认情况下,Web应用程序将在所有HTTP端点上使用“basic”身份验证。 要向Web应用程序添加方法级安全性,您还可以使用所需的设置添加@EnableGlobalMethodSecurity。 有关更多信息,请参见“[Spring Security Reference](http://docs.spring.io/spring-security/site/docs/4.2.2.RELEASE/reference/htmlsingle#jc-method)”。 默认的AuthenticationManager有一个用户(用户名'user'和随机密码,在应用程序启动时以INFO级别打印) ``` Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35 ``` > 如果您调整日志记录配置,请确保将org.springframework.boot.autoconfigure.security类别设置为记录INFO消息,否则将不会打印默认密码。 您可以通过提供security.user.password来更改密码。 这个和其他有用的属性通过 [SecurityProperties](https://github.com/spring-projects/spring-boot/tree/v1.5.2.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java)(属性前缀“security”)进行外部化。 默认的安全配置在SecurityAutoConfiguration和从那里导入的类中实现(用于Web安全的SpringBootWebSecurityConfiguration和用于认证配置的AuthenticationManagerConfiguration,这在非Web应用程序中也是相关的)。 要完全关闭默认的Web应用程序安全配置,您可以使用@EnableWebSecurity添加一个bean(这不会禁用身份验证管理器配置或Actuator的安全性)。 要定制它,您通常使用WebSecurityConfigurerAdapter类型的外部属性和bean(例如添加基于表单的登录)。 要关闭身份验证管理器配置,您可以添加AuthenticationManager类型的bean,或者通过将AuthenticationManagerBuilder自动连接到您的一个@Configuration类中的方法来配置全局AuthenticationManager。 Spring Boot示例中有几个安全应用程序可以让您开始使用常见的[用例](https://github.com/spring-projects/spring-boot/tree/v1.5.2.RELEASE/spring-boot-samples/)。 您在Web应用程序中获得的基本功能包括: * 具有内存存储和单个用户的AuthenticationManager Bean(请参阅用于用户属性的SecurityProperties.User)。 * 对于常见的静态资源位置,忽略(不安全)路径(/css/**, /js/**, /images/**, /webjars/** and **/favicon.ico)。 * HTTP所有其他端点的baseic security 。 * 安全事件发布到Spring的ApplicationEventPublisher(成功、不成功的身份验证、拒绝访问)。 * 默认情况下,Spring Security提供的常见的底层功能(HSTS,XSS,CSRF,缓存)都是打开的。 所有上述可以使用外部属性(security.*)打开、关闭或修改。 要覆盖访问规则而不更改任何其他自动配置的功能,请添加一个带有@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)的WebSecurityConfigurerAdapter类型的Bean,并配置它以满足您的需要。 > 默认情况下,WebSecurityConfigurerAdapter将匹配任何路径。 如果您不想完全覆盖Spring Boot自动配置的访问规则,您的适配器必须显式配置您要覆盖的路径。 ### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#281-oauth2)28.1 OAuth2 如果您的类路径中有spring-security-oauth2,您可以利用一些自动配置来轻松设置授权或资源服务器。 有关完整的详细信息,请参阅“[Spring Security OAuth 2开发人员指南](http://projects.spring.io/spring-security-oauth/docs/oauth2.html)”。 #### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2811-授权服务器)28.1.1 授权服务器 要创建授权服务器并授予访问令牌,您需要使用@EnableAuthorizationServer并提供security.oauth2.client.client-id和security.oauth2.client.client-secret]属性。 客户端将为您注册在内存中。 ``` $ curl client:secret@localhost:8080/oauth/token -d grant_type=password -d username=user -d password=pwd ``` /token 端点的基本身份验证凭证是client-id和client-secret。 用户凭据是普通的Spring Security用户details (在Spring引导中默认为“user”和随机密码)。 要关闭自动配置并自行配置授权服务器功能,只需添加一个类型为AuthorizationServerConfigurer的@Bean。 #### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2812-资源服务器)28.1.2 资源服务器 要使用访问令牌(token),您需要一个资源服务器(可以与授权服务器相同)。 创建资源服务器很简单,只需添加@EnableResourceServer并提供一些配置,以允许服务器解码访问令牌。 如果您的应用程序也是授权服务器,则它已经知道如何解码令牌,无需做其他事情。 如果你的应用程序是一个独立的服务,那么你需要给它一些更多的配置,以下选项之一: * security.oauth2.resource.user-info-uri使用/me资源(例如PWS上的 * security.oauth2.resource.token-info-uri使用令牌解码端点(例如,PWS上的 如果您同时指定user-info-uri和token-info-uri,那么您可以设置一个标志,表示优先于另一个(prefer-token-inf=true是默认值)。 或者(不是user-info-uri或token-info-uri的情况)如果令牌是JWT,您可以配置security.oauth2.resource.jwt.key-value来本地解码(key是验证密钥verification key)。 验证密钥值是对称秘密或PEM编码的RSA公钥。 如果您没有密钥,并且它是公开的,您可以提供一个可以使用security.oauth2.resource.jwt.key-uri下载的URI(具有“value”字段的JSON对象)。 例如在PWS上: ``` $ curl https://uaa.run.pivotal.io/token_key {"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"} ``` 如果您使用security.oauth2.resource.jwt.key-uri,则应用程序启动时需要运行授权服务器。 如果找不到密钥,它将记录一个警告,并告诉您如何解决该问题。 > 如果您使用security.oauth2.resource.jwt.key-uri,则应用程序启动时需要运行授权服务器。 如果找不到密钥,它将会在日志记录一个警告,并告诉您如何解决该问题。 OAuth2资源由order security.oauth2.resource.filter-order的过滤器链保护,默认情况下保护执行器(actuator)端点的过滤器(所以执行器(actuator)端点将保留在HTTP Basic上,除非更改顺序)。 ### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#282-user-info中的令牌类型)28.2 User Info中的令牌类型 Google和某些其他第三方身份认证提供商对在header中发送到用户信息端点的令牌类型名称更为严格。 默认值为“Bearer”,适合大多数提供程序并匹配规范,但如果需要更改,可以设置security.oauth2.resource.token-type。 ### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#283-自定义用户信息resttemplate)28.3 自定义用户信息RestTemplate 如果您有user-info-uri,则资源服务器功能在内部使用OAuth2RestTemplate来获取用户身份验证信息。 这是以UserInfoRestTemplateFactory类型的@Bean提供的。 大多数提供程序的默认值应该是能满足正常使用,但有时您可能需要添加其他拦截器,或者更改请求验证器(例如:令牌如何附加到传出请求)。 进行自定义,只需创建一个类型为UserInfoRestTemplateCustomizer的bean - 它具有一个方法,在bean创建之后但在初始化之前将被调用。 这里定制的rest模板只能在内部进行验证。 或者,您可以定义自己的UserInfoRestTemplateFactory @Bean来完全控制。 要在YAML中设置RSA密钥值,请使用“pipe”继续标记将其分割成多行(“|”),并记住缩进键值(它是标准的 YAML 语言功能)。 例: ``` security: oauth2: resource: jwt: keyValue: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC... -----END PUBLIC KEY----- ``` #### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2831-client)28.3.1 Client 要使您的 web-app 进入OAuth2客户端,您可以简单地添加@ EnableOAuth2Client,Spring Boot将创建一个OAuth2ClientContext和OAuth2ProtectedResourceDetails,这些是创建OAuth2RestOperations所必需的。 Spring Boot不会自动创建这样的bean,但是您可以轻松创建自己的bean: ``` @Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext, OAuth2ProtectedResourceDetails details) { return new OAuth2RestTemplate(details, oauth2ClientContext); } ``` > 您可能需要添加限定符并查看您的配置,因为您的应用程序可能会定义多个RestTemplate。 此配置使用security.oauth2.client.*作为凭据(可能与授权服务器中使用的相同),但另外还需要知道授权服务器中的授权和令牌URI。 例如: application.yml. ``` security: oauth2: client: clientId: bd1c0a783ccdd1c9b9e4 clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1 accessTokenUri: https://github.com/login/oauth/access_token userAuthorizationUri: https://github.com/login/oauth/authorize clientAuthenticationScheme: form ``` 当您尝试使用OAuth2RestTemplate时,具有此配置的应用程序将重定向到Github进行授权。 如果您已经登录Github,您甚至不会注意到它已经被认证。 如果您的应用程序在端口8080上运行(在Github或其他提供商注册自己的客户端应用程序以获得更大的灵活性),这些特定的凭据才会起作用。 要限制客户端在获取访问令牌时要求的范围,您可以设置security.oauth2.client.scope(逗号分隔或YAML中的数组)。 默认情况下,scope是空的,由授权服务器决定其默认值,通常取决于客户端注册中的设置。 > 还有一个security.oauth2.client.client-authentication-scheme的设置,默认为“header”(但是如果像Github那样,您可能需要将其设置为“form”,例如,您的OAuth2提供程序不喜欢header 认证)。 事实上,security.oauth2.client.*属性绑定到AuthorizationCodeResourceDetails的一个实例,因此可以指定其所有的属性。 > 在非Web应用程序中,您仍然可以创建一个OAuth2RestOperations,它仍然连接到security.oauth2.client.*配置中。 在这种情况下,它是一个“客户端凭据令牌授予”,您如果使用它就请求它(并且不需要使用@EnableOAuth2Client或@EnableOAuth2Sso)。为了防止定义基础设施,只需从配置中删除security.oauth2.client.client-id(或使其成为空字符串)。 #### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#2832-单点登录)28.3.2 单点登录 OAuth2客户端可用于从提供商获取用户详细信息(如果此类功能可用),然后将其转换为Spring Security的身份验证令牌。 以上资源服务器通过user-info-uri属性支持此功能这是基于OAuth2的单点登录(SSO)协议的基础,Spring Boot可以通过提供@ EnableOAuth2Sso注解来轻松加入。 上面的Github客户端可以通过添加该注释并声明在何处查找端点(除了上面列出的security.oauth2.client.*配置)外,还可以保护所有资源并使用Github/user/endpoint进行身份验证: application.yml. ``` security: oauth2: ... resource: userInfoUri: https://api.github.com/user preferTokenInfo: false ``` 由于默认情况下所有路径都是安全的,所以没有可以向未经身份验证的用户显示“家”页面,并邀请他们登录(通过访问/登录路径或由security.oauth2.sso.login-path指定的路径) 。 由于默认情况下所有路径都是要求安全的,所以没有可以向未经身份验证的用户显示“home”页面,并邀请他们登录(通过访问/login 路径或由security.oauth2.sso.login-path指定的路径) 。 要自定义保护的访问规则或路径,因此您可以添加“home”页面,例如,@EnableOAuth2Sso可以添加到WebSecurityConfigurerAdapter,并且注解将使其被修饰和增强,以使所需的/login路径可以工作。 例如,这里我们简单地允许未经身份验证的访问“/"下的主页面,并保留其他所有内容的默认值: ``` @Configuration public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override public void init(WebSecurity web) { web.ignore("/"); } @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/**").authorizeRequests().anyRequest().authenticated(); } } ``` ### [](file:///C:/Users/geekidentity/AppData/Local/Youdao/YNote/markdown/index.html#284-actuator-security)28.4 Actuator Security 如果Actuator也在使用中,您会发现: * 即使应用程序端点不安全,管理端点也是安全的。 * Security 事件将转换为AuditEvent实例,并发布到AuditEventRepository。 * 默认用户将具有ACTUATOR角色以及USER角色。 Actuator的安全功能可以使用外部属性(management.security.*)进行修改。要覆盖应用程序访问规则,请添加一个类型为WebSecurityConfigurerAdapter的@Bean,如果您不想覆盖执行程序访问规则,则使用@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)或@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)覆盖执行器访问规则。