zoukankan      html  css  js  c++  java
  • Spring Security

    Spring Security

    一、简介

    Spring Security从两个角度解决安全问题:

    1)使用Servlet规范中的Filter保护Web请求并限制URL级别的访问。

    2)使用Spring AOP保护方法调用-----借助于于对象代理和使用通知,

    能够确保只有具备适当权限的用户才能访问安全保护的方法。

    1.过滤Web请求

    Spring Security借助一系列的Servlet Fliter来过滤web请求。我们只需要配置一个Filter。

    DelegatingFilterProxy是一个特殊的Servlet Filter,它将工作委托给一个javax.servlet.Filter实现类,

    这个实现类作为一个<bean>注册在Spring应用上下文中。

    有一个名为springSecurityFilterChain的Filter bean, DelegatingFilterProxy会将过滤逻辑委托给它。

    以Java方式配置DelegatingFilterProxy:

    public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer{
    }

    配置好DelegatingFilterProxy后,它会拦截发往应用中的请求,并将请求委托给ID为springSecurityFilterChain bean。

    2.编写简单的安全性配置

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
    }

    Spring Security必须配置在实现了WebSecurityConfigurger的bean中,或者

    扩展WebSecurityConfigurerAdapter。

    通过重载WebSecurityConfigurerAdapter中方法,可以指定web安全的细节。

    二、用户存储

    用户存储:也就是用户名、密码以及其他信息存储的地方,在进行决策的时候,会对其进行检索。

    1.基于内存的用户存储

    方式:重载WebSecurityConfigureAdapter中的configure方法。

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            //启用内存用户存储
            //and链接多个用户配置
            auth.inMemoryAuthentication().withUser("user")
                    .password("password").roles("USER").and()
                    .withUser("tang").password("password").roles("USER", "ADMIN");
        }

    3.基于数据库表进行认证

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
        @Autowired
        DataSource dataSource;
        
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            auth.jdbcAuthentication().dataSource(dataSource);
        }
    }

    重写默认的用户查询功能: 

    Spring Security内部默认的查询sql:

    配置自己的查询:

        @Autowired
        DataSource dataSource;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            auth.jdbcAuthentication().dataSource(dataSource)
                    .usersByUsernameQuery("select username, password, flag "
                    + "from user_info where username=?").authoritiesByUsernameQuery(
                            "select username, 'ROLE_USER' from user_info where username=?"
            );
        }

    使用转码后的密码: 

    上面的认证查询会预期密码存储在数据库中,如果数据库中的密码进行了转码的话,

    那么认证就会失败,因为它与用户提交的明文密码并不匹配。为了解决这个问题,我们

    需要借助passwordEncoder()方法指定一个密码转码器。

    public interface PasswordEncoder {
        String encode(CharSequence var1);
        boolean matches(CharSequence var1, String var2);
        default boolean upgradeEncoding(String encodedPassword) {
            return false;
        }
    }
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            auth.jdbcAuthentication().dataSource(dataSource)
                    .usersByUsernameQuery("select username, password, flag "
                    + "from user_info where username=?").authoritiesByUsernameQuery(
                            "select username, 'ROLE_USER' from user_info where username=?"
            ).passwordEncoder(new StandardPasswordEncoder("xsf"));
        }

     4.配置自定义的用户服务

    假设需要认证的用户存储在非关系型数据库中,如Mongo或Neo4j,这种情况下

    我们需要提供一个自定义的UserDetailService接口实现。

    public interface UserDetailsService {
        UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }

    要做的就是实现loadUserByUsername()方法,根据给定的用户名查找用户。该接口不关心,也不知道底层所使用的用户存储。

    为了使用UserDetailService来认证用户,我们可以通过AuthenticationManagerBuilder的userDetailsService()方法设置它。

    三、拦截请求

    方法:通过重载configure(HttpSecurity),为不同的URL路径有选择地应用安全性。

    @Configuration
    @EnableWebSecurity  //启用Spring Security的Web安全支持,并提供Spring MVC集成
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        //定义了哪些URL路径应该被保护,哪些不应该
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/", "/home").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                    .logout()
                    .permitAll();
        }
    }

    authenticated()要求在执行该请求时,必须已经登陆了应用。如果用户没有认证的话,Spring Security的Filter将会捕获该请求,

    并将用户重定向到应用的登陆页面。同时,permitAll()方法允许请求没有任何安全限制。

     1.使用Spring表达式进行安全保护

    借助access()方法,可以将SpEL作为声明访问限制的一种方式。例如:

    http.authorizeRequests()
                    .antMatchers("/", "/home")
                    .access("hasRole('ROLE_USER') and hasIpAddress(192.168.1.2)");

    2.强制通道的安全性

    传递到configure()方法中的HttpSecurity对象,有一个requiresChannel()方法,

    借助这个方法能够为各种URL模式声明所要求的通道。

    http.requiresChannel().antMatchers("/home").requiresSecure(); //需要https

    四、认证用户

    1.启用HTTP Basic认证

    HTTP Basic认证会直接通过HTTP请求本身,对要访问的应用程序的用户进行认证。

    本质上,它是一个HTTP401响应,表面必须要在请求中包含一个用户名和密码。

    方法:在HttpSecurity对象上调用httpBasic()即可。

    2.启用Remember-me功能

    方法:在HttpSecurity对象上调用remeberMe()即可。

    @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin()
                    .loginPage("/login")
                    .and()
                    .rememberMe()
                    .tokenValiditySeconds(2419200)
                    .key("tangKey");

    存储在cookie中的token包含用户名、密码、过期时间和一个私钥----在写入cookie前都

    进行了MD5哈希。默认情况下,私钥名为SpringSecured,这里我们更改了它。

    用户需要操作:

    <input id="remeber_me" name="remeber_me" type="checkbox"/>

    3.退出

    退出功能是通过Servlet容器中的Filter实现的,这个Filter会拦截针对"/logout"的请求。添加退出功能:

    <a th:href="@{/logout}">Logout</a>

    如果希望用户被重定向到其他页面:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin()
                    .loginPage("/login")
                    .and()
                    .logout()
                    .logoutSuccessUrl("/");     //退出成功后重定向到/
        }

    五、保护视图

    1.使用Spring Security的JSP标签

    首先在JSP页面中声明该标签库:

    <%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

    Hello <security:authentication property="principal.username">

    条件性的渲染内容: 

    <sec:authorize access="hasRole('ROLE_TANG')"

    因为已经在Spring Security中声明了安全性约束:

    <security:authorize url="/admin">
        <spring:url value="/admin" var="admin_url" />
        <br/><a href="${admin_url}">Admin</a>
    </security>
  • 相关阅读:
    PHP Jquery
    PHP TPinfo表的增删改查
    PHP TP验证码
    PHP TP表单验证
    PHP TP增删改
    8月21日 仿163邮箱中遇到的问题及解决(三)
    8月20日 仿163邮箱中遇到的问题及解决(二)
    8月12日 仿163邮箱中遇到的问题及解决(一)
    8月7日 使用Jquery做表格的隔行变色,点击事件
    6月17日 TP表单验证
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/10572919.html
Copyright © 2011-2022 走看看