zoukankan      html  css  js  c++  java
  • Spring Security 之API 项目安全验证(基于basic-authentication)

    ===================================
    Basic Authorization 规范
    ===================================
    Request 头部:
    Authorization: Basic QWxpY2U6MTIzNDU2
    其中 QWxpY2U6MTIzNDU2 是user:pwd做 base64 编码, 格式是 user:pwd

    response 头部:
    WWW-Authenticate: Basic realm="My Realm"

    按照 RFC 规范, 相同的 realm(域) 下的web page 将共享同样的 credentials, 所以推荐 realm 取值为 application name. realm 大小写敏感, 可以包含空格.


    ===================================
    Rest API 示例
    ===================================
    功能:
    1. 演示如何启用 Basic Authorization
    2. 如何使用 RestTemplate 访问受保护的 API接口

    -----------------------------------
    SecurityConfig 代码
    -----------------------------------
    关键点有:
    0. 对于 /api/** 需要 ROLE_ADMIN 角色的账号访问, 对于 /guest/** 路径允许匿名访问.
    1. 使用 HttpSecurity.httpBasic() 启用 Basic Authorization.
    2. 使用 HttpSecurity.httpBasic().realmName() 设置 realm.
    3. 使用 HttpSecurity.httpBasic().authenticationEntryPoint() 设置 BasicAuthenticationEntryPoint 对象, 如果一个请求通过验证, 该对象会自动为web response设定 WWW-Authenticate header, 如果未通过, 该对象会自动将HttpStatus设置为UNAUTHORIZED.
    4. 显式启用了 STATELESS session 管理机制, 经测试,Spring Security 在Basic Authorization模式下, session自动就处于了 STATELESS 状态.
    5. 对于 HttpMethod.OPTIONS 请求, 允许匿名访问. API 项目应该开放 OPTIONS 查询权限.

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        //@formatter:off
        @Override
        public void configure(AuthenticationManagerBuilder builder) throws Exception {
            builder.inMemoryAuthentication()
                    .withUser("123").password("123").roles("USER")
                    .and()
                    .withUser("ADMIN").password("ADMIN").roles("ADMIN");
        }
        //@formatter:on
    
        private static String REALM = "MY SPRING SECURITY DEMO";
    
        // @formatter:off
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
               .authorizeRequests()
                   // 对于/api 路径下的访问需要有 ROLE_ADMIN 的权限
                  .antMatchers("/api/**").hasRole("ADMIN")
                   // 对于/guest 路径开放访问
                  .antMatchers("/guest/**").permitAll()
                   // 其他url路径之需要登陆即可.
                  .anyRequest().authenticated()
                  .and()
               //启用 basic authentication
              .httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthenticationEntryPoint())
                  .and()
               //不创建 session
              .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
        // @formatter:on
    
        /**
         * 生成 BasicAuthenticationEntryPoint 对象, 在该对象的支持下, 通过验证的请求, 返回的response 将会自动加上
         * WWW-Authenticate Header.  在该对象的支持下, 未通过验证的请求, 返回的 response 为 UNAUTHORIZED 错误.
         *
         * @return
         */
        @Bean
        public BasicAuthenticationEntryPoint getBasicAuthenticationEntryPoint() {
            BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
            entryPoint.setRealmName(REALM);
            return entryPoint;
        }
    
        /*
         * 开放 Options 请求
         */
        @Override
        public void configure(WebSecurity web) throws Exception {
            // TODO Auto-generated method stub
            web.ignoring()
                    .antMatchers(HttpMethod.OPTIONS, "/**");
        }
    
        @SuppressWarnings("deprecation")
        @Bean
        public NoOpPasswordEncoder passwordEncoder() {
            BasicAuthenticationEntryPoint a;
            return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        }
    }


    -----------------------------------
    受控 API Rest 类
    -----------------------------------
    对于 /api/** url需要 ROLE_ADMIN 角色的账号访问, 这里的代码很简单.

    /*
     * 需要进行 Basic Auth 的API
     */
    @RestController
    @RequestMapping("/api")
    class ApiController {
    @GetMapping(
    "/books") public String getBooks() { return "API book"; } }

    直接访问受控url, 弹出浏览器内置的登陆框, 见下图, 符合预期. 


    -----------------------------------
    RestTemplate 访问 Basic Authorization的API
    -----------------------------------
    关键点:
    使用了 restTemplateBuilder.basicAuthorization(user,pwd).build() 来构建 RestTemplate, 这样的 RestTemplate 会自动在Request上加 Authorization Header.

    /*
     * RestTemplate 访问 Basic Authorization的API的示例
     */
    @RestController
    @RequestMapping("/guest")
    class DefaultController {
    
        @GetMapping("/mybooks")
        @ResponseBody
        public String getMyBook() {
            return "My Book";
        }
    
        private RestTemplate restTemplate;
    
        @Autowired
        private RestTemplateBuilder restTemplateBuilder;
    
        @Autowired
        void setRestTemplate(RestTemplateBuilder restTemplateBuilder) {
             restTemplate = restTemplateBuilder.basicAuthorization("ADMIN", "ADMIN")
             .build();
        }
    
        @GetMapping("/apibooks")
        @ResponseBody
        public String getApiBooks() {
            return restTemplate.getForObject("http://localhost:8080/api/books", String.class);
    
        }
    }

    访问 http://localhost:8080/guest/apibooks 地址,  无需登陆即可得到 api 结果, 见下图, 符合预期. 

    ===================================
    参考
    ===================================
    http://websystique.com/spring-security/secure-spring-rest-api-using-basic-authentication/
    http://www.bytestree.com/spring/restful-web-services-authentication-authorization/
    https://www.baeldung.com/spring-security-basic-authentication

  • 相关阅读:
    [异常解决] JLINK 与STM32的SWD连接接线方式
    2、利用蓝牙定位及姿态识别实现一个智能篮球场套件(二)——CC2540/CC2541基于广播的RSSI获得
    [Intel Edison开发板] 05、Edison开发基于MRAA实现IO控制,特别是UART通信
    1、利用蓝牙定位及姿态识别实现一个智能篮球场套件(一)——用重写CC2541透传模块做成智能手环
    [Intel Edison开发板] 04、Edison开发基于nodejs和redis的服务器搭建
    [Intel Edison开发板] 03、Edison开发IDE入门及跑官方提供的DEMO
    [Intel Edison开发板] 02、Edison开发板入门
    [Intel Edison开发板] 01、Edison开发板性能简述
    [每日电路图] 10、两种MOS管的典型开关电路
    [每日电路图] 9、介绍一种低价简单的4.2V锂电池充电及稳压(LDO)电路——RT9193,SD8017
  • 原文地址:https://www.cnblogs.com/harrychinese/p/SpringBoot_security_api_basic_auth.html
Copyright © 2011-2022 走看看