zoukankan      html  css  js  c++  java
  • spring security基本知识(一)

    spring security基本知识(一)

    Spring Security是为基于Spring的应用程序提供声明式安全保护的安全 性框架。Spring Security提供了完整的安全性解决方案,它能够在Web 请求级别和方法调用级别处理身份认证和授权。因为基于Spring框 架,所以Spring Security充分利用了依赖注入(dependency injection, DI)和面向切面的技术。Spring Security借助一系列Servlet Filter来提供各种安全性功能。但是这一系列Servlet Filter并不需要我们在web.xml或WebApplicationInitializer中配置多个Filter。

     

    要实现自定义security配置,最核心的就是重写“WebSecurityConfigurerAdapter”。

    相关解释说明

    注解 @EnableWebSecurity

    在 Spring boot 应用中使用 Spring Security,用到了 @EnableWebSecurity注解。

    抽象类 WebSecurityConfigurerAdapter

    一般情况,会选择继承 WebSecurityConfigurerAdapter 类。WebSecurityConfigurerAdapter 提供了一种便利的方式去创建 WebSecurityConfigurer的实例,只需要重写 WebSecurityConfigurerAdapter 的方法,即可配置拦截什么URL、设置什么权限等安全控制

    WebSecurityConfigurerAdapter里的重要方法:

    1、configure(HttpSecurity)通过重载,配置如何通过拦截器保护请求。

    2、configure(AuthenticationManagerBuilder)通过重在配置user-detail 服务。

    3、configure(WebSecurity)通过重载,配置Spring Security的Filter链

    详细说明:

    1、 configure(HttpSecurity)

    我们知道,在引入security依赖后,启动项目在登陆时就会出现弹窗让我们来输入账号密码。那是因为WebSecurityConfigurerAdapter自身已经实现了一套安全过滤,但这并不是我们想要的。先来看一下WebSecurityConfigurerAdapter的configure(HttpSecurity) 方法如下。HttpSecurity 实现了一个 HttpSecurityBuilder 接口,这是一个构造器接口,因此可以使用构造器典型的链式调用风格.通过调用authorizeRequests()和 anyRequest()。

        @Override
        public void configure(HttpSecurity http) throws Exception {
                    http.authorizeRequests().anyRequest().authenticated()
                            .and().formLogin()
                            .and().httpBasic();
        }

    我们需要自定义符合我们需求的安全过滤体系,重载后的方法如下。

        /**
         * 匹配 "/" 路径,不需要权限即可访问
         * 匹配 "/user" 及其以下所有路径,都需要 "USER" 权限
         * 登录地址为 "/login",登录成功默认跳转到页面 "/user"
         * 退出登录的地址为 "/logout",退出成功后跳转到页面 "/login"
         * 默认启用 CSRF
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/").permitAll()
                    .antMatchers("/user/**").hasRole("USER")
                    .and().formLogin().loginPage("/login").defaultSuccessUrl("/user")
                    .and().logout().logoutUrl("/logout").logoutSuccessUrl("/login");
        }

    当然,HttpSecurity的方法还有很多,比如csrf()、sessionManagement()等,后续再详细说明。

    2、configure(AuthenticationManagerBuilder)

    Spring Security非常灵活,能够基于各种数据存储来认证用户。它内置了许多常见的用户存储场景。如: 内存,关系型数据库,以及LDAP。当然,我们也可以编写并插入自定义的用户存储实现。

    查看AuthenticationManagerBuilder源码,有如下方法:

        public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() throws Exception {
            return (InMemoryUserDetailsManagerConfigurer)this.apply(new InMemoryUserDetailsManagerConfigurer());
        }//内存
    
        public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
            return (JdbcUserDetailsManagerConfigurer)this.apply(new JdbcUserDetailsManagerConfigurer());
        }//jdbc
    
        public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(T userDetailsService) throws Exception {
            this.defaultUserDetailsService = userDetailsService;
            return (DaoAuthenticationConfigurer)this.apply(new DaoAuthenticationConfigurer(userDetailsService));
        }//用户自定义
    
        public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication() throws Exception {
            return (LdapAuthenticationProviderConfigurer)this.apply(new LdapAuthenticationProviderConfigurer());
        }//ldap

    1)使用基于内存的用户存储

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("user_name1").password("123456").roles("USER")
                    .and()
                    .withUser("user_name1").password("123456").roles("ADMIN");
        }

     2)基于JDBC

        @Autowired
        private javax.sql.DataSource dataSource;
    
        //基于数据库表的用户存储
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.jdbcAuthentication()
                    .dataSource(dataSource);
    
        }

    在这里我们只需要配置一个dataSource即可,这样就可以访问关系型数据库了。其中 dataSource是通过自动装配的技巧得到的。在springboot下 dataSource 是自动装配的。我们只需要引入如下依赖

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>

    并在appliciation.properties 中配置spring.datasource 相关属性即可。

    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true
    spring.datasource.username=root
    spring.datasource.password=root

    Spring Boot就会使用该配置创建一个DataSource。并装配为Spring的一个bean。因此我们可以直接使用 @Autowired 进行注入。

    好了,直到目前为止,对基于数据库的用户存储已经配置完毕,你可能回想,那既然基于数据库了,肯定要在数据库创建相应的表了。那表结构又是怎么样的呢?

    auth.jdbcAuthentication()方法返回的是JdbcUserDetailsManagerConfigurer,他除了dataSource(dataSource)方法还有,

    public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) throws Exception {
            this.getUserDetailsService().setUsersByUsernameQuery(query);
            return this;
        }
    
        public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) throws Exception {
            this.getUserDetailsService().setAuthoritiesByUsernameQuery(query);
            return this;
        }
    
        public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) throws Exception {
            JdbcUserDetailsManager userDetailsService = this.getUserDetailsService();
            userDetailsService.setEnableGroups(true);
            userDetailsService.setGroupAuthoritiesByUsernameQuery(query);
            return this;
        }

    这几个方法。他们在JdbcDaoImpl中有默认的SQL。

    private String authoritiesByUsernameQuery = "select username,authority from authorities where username = ?";
    private String groupAuthoritiesByUsernameQuery = "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id";
    private String usersByUsernameQuery = "select username,password,enabled from users where username = ?";

    当然我们也可以根据业务自己定义SQL

    @Autowired
        private DataSource dataSource;
    
        //基于数据库表的用户存储
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.jdbcAuthentication()
                    .dataSource(dataSource)
                    .usersByUsernameQuery("select username,password,enabled,email from users where username=?")
                    .authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
                    .groupAuthoritiesByUsername("select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id");
        }

    我们就是要依据这些SQL来创建表格,或者可以反过来说。我们定义好表格后使用自定义的SQL。

  • 相关阅读:
    windows10上运行Linux Bash Shell
    作为DBA,该不该买macbook
    MySQL5.5 同步到5.7 遇到一坑,导致主从断掉
    CentOS7下安装SQL SERVER linux版
    MySQL设置utf8mb4,支持emoji并验证
    Nginx在window环境下设置二级访问目录
    win10 如何给定脑固定ip
    react中 getFieldProps 方法定义说明
    node中npm结构详解以及自定义npm包上传到npm教程
    nodejs npm包管理常用命令介绍
  • 原文地址:https://www.cnblogs.com/cuiqq/p/11012885.html
Copyright © 2011-2022 走看看