保护Web应用

从Web应用程序中保护用户数据:Web应用程序的可伸缩性和容量优化 分布式数据存储系统的核心原理是数据分片和数据复制。数据分片是指将一个大型的数据集分成多个小份,分别存储在不同的服务器上。这样可以减少单个服务器的负担,提高系统的可扩展性。数据复制是指将某个数据点的所有数据副本分别存储在不同的服务器上,以保证数据的可靠性和容错性。本文将介绍如何在 Web 应用程序中保护用户数据,实现数据的可靠性和容错性。用户通过登录进入 Web 应用程序后,我们将为其保存用户名和密码,并将其存储到分布式数据存储系统中。 阅读详情

保护Web应用

Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架。Spring Security提供完整的安全性解决方案,能够在Web请求级别和方法调用级别处理身份认证和授权,充分利用依赖注入和面向切面技术。Spring Securigy从两个角度解决安全性问题,使用Servlet规范中的Filter保护Web请求并限制URL级别的访问;使用Spring AOP保护方法调用,借助于对象代理和使用通知,能够确保只有具备适当权限的用户才能访问安全保护的方法

理解Spring Security的模块

Spring Security 3.2一共分为11个模块,应用程序的类路径下至少要包含核心和配置这两个模块:

  • ACL:支持通过访问控制列表为域对象提供安全性

  • 切面:当使用Spring Security注解时,会使用基于AspectJ的切面,而不是使用标准的Spring AOP

  • CAS客户端:提供与Jasig的中心认证服务进行集成的功能

  • 配置:包含通过XML和Java配置Spring Security的功能支持

  • 核心:提供Spring Security基本库

  • 加密:提供加密和密码编码的功能

  • LDAP:支持基于LDAP进行认证

  • OpenID:支持使用OpenID进行集中是认证

  • Remoting:提供了对Spring Remoting的支持

  • 标签库:Spring Security的JSP标签库

  • Web:提供Spring Security基于Filter的Web安全性支持

过滤Web请求

Spring Security借助一系列Servlet Filter来提供各种安全性功能,我们只需配置一个Filter就可以实现。DelegatingFilterProxy是一个特殊的Servlet Filter,他将工作委托给一个javax.servlet.Filter实现类,这个实现类作为一个注册在spring应用上下文中

通过web.xml配置

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

DelegatingFilterProxy将过滤逻辑委托给springSecurityFilterChain

以Java方式配置

借助WebApplicationInitializer以Java方式配置DelegatingFilterProxy

    public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer{

    }

AbstractSecurityWebApplicationInitializer实现了WebApplicationInitializer,Spring会用它在Web容器中注册DelegatingFilterProxy。也可以重载appendFilters()或insertFilters()方法来注册自己选择的Filter。不管通过web.xml还是Java方式配置DelegatingFilterProxy,它都会拦截发往应用的请求,并将请求委托给ID为springSecurityFilterChain bean。

springSecurityFilterChain本身是另一个特殊的Filter,它被称为FilterChainProxy,它可以链接任意一个或多个其他的Filter,Spring Security依赖一系列Servlet Filter来提供不同的安全特性,但是几乎不需要知道这些细节,不需要显示申明springSecurityFilterChain以及它所连接在一起的其他Filter

编写简单的安全性配置

Spring Security最简单的Java配置

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter{

    }

@EnableWebSecurity注解用于启动Web安全功能,Spring Security必须配置在一个实现了WebSecurityConfiger的bean中,或者扩展了WebSecurityConfigurerAdapter

如果使用Spring MVC开发则可以使用@EnableWebMvcSecurity替代它,注解还配置了一个Spring MVC参数解析器,这样处理器方法能够通过带有@AuthenticationPrincipal注解的参数获得认证用户的principal,他同时还配置了一个bean,在使用Spring表单绑定标签库来定义表单时,这个bean会自动添加一个隐藏的跨站请求伪造token输入域。

我们可以通过重载WebSecurityConfigurerAdapter的三个configure()方法来配置Web安全性:

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

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

  • configure(AuthenticationManagerBuilder):通过重载,配置user-detail服务

默认configure(HttpSecurity)实现

    protected void configure(HttpSecurity http) throw Exception{
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin().and()
            .httpBasic();
    }

为了使Spring Security满足我们的需求我们需要:

  • 配置用户存储

  • 指定那些请求需要认证,那些请求不需要认证,以及所需要的权

选择查询用户详细信息的服务

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

使用基于内存的用户存储

通过重载WebSecurityConfigurerAdapter的configure(AuthenticationManagerBuilder)方法,AuthenticationManagerBuilder方法可以用来配置Spring Security对认证的支持,通过inMemoryAuthentication()方法,可以开启、配置并任意填充基于内存的用户存储

    @Configuration
    @EnableWebMvcSecurity
    public void SecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throw Exception{
            auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER", "ADMIN");
        }
    }

roles()方法是authorities()方法的简写形式,roles()方法所给的值会添加一个“ROLE_”前缀,并将其作为权限授予给用户。withUser()方法返回的是UserDetailsManagerConfigurer.UserDetailsBuider,这个对象设置了多个进一步配置用户的方法:

  • accountExpired(boolean):定义账号是否已经过期

  • accountLocked(boolean):定义账号是否已经锁定

  • and():用来连接配置

  • authorities(GrantedAuthority…):授予某个用户一项或多项权限

  • authorities(List<? extends GrantedAuthority>):授予某个用户一项或多项权限

  • authorities(String…):授予某个用户一项或多项权限

  • credentialsExpired(boolean):定义凭证是否已经过期

  • disabled(boolean):定义账号是否已被禁用

  • password(String):定义用户密码

  • roles(String…):授予某个用户一项或多项角色

对于调试和开发人员测试来讲,基于内存的用户存储很有用,但对于生产环境最好选择某种类型的数据库

基于数据库表进行认证

用户数据通常会存储在关系型数据库中,并通过JDBC进行访问,为配置Spring Security使用以JDBC为支撑的用户存储,可以使用jdbcAuthentication()方法

    @Autowired
    DataSource dataSource

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
            .jdbcAuthentication()
            .dataSource(dataSource);
    }

重写默认的用户查询功能

Spring Security预期存在某些存储用户数据的表,内置查找用户信息时所执行的SQL如下

    public static final String DEF_USERS_BY_USERNAME_QUERY = 
        "select username,password,enabled " +
        "from users " +
        "where username = ?";
    public static final String DEF_AUTHORITOES_BY_USERNAME_QUERY = 
        "select username,authority "+
        "from authorities "+
        "where username = ?";
    public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = 
        "select g.id, g.group_name, ga.authority "+
        "from groups g, group_members gm, group_authorities ga "+
        "where gm.username = ? " +
        "and g.id = ga.gorup_id " +
        "and g.id = gm.group_id";

替换内置查询sql,使用自定义查询sql

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
            .jdbcAuthtication()
            .userByUsernaneQuery(
                "select username, password, true " +
                "from Spitter where username = ?")
            .authoritiesByUsernameQuery(
                "select username, 'ROLE_USER' from Spitter where username = ?");
            .groupAuthoritiesByUsername("...");
    }

将默认的SQL查询替换为自定义的设计时,很重要的一点就是要遵循查询的基本协议,所有查询都将用户名作为唯一的参数

使用转码后的密码

数据库中用户密码通常都是进行转码存储的,Spirng Security需要借助passwordEncoder()方法指定一个密码转换器

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
            .jdbcAuthentication()
            .usersByUsernameQuery(
               "select username, password, true " +
                "from Spitter where username = ?")
            .authoritiesByUsernameQuery(
                "select username, 'ROLE_USER' from Spitter where username = ?");
            .groupAuthoritiesByUsername("...")
            .passwordEncoder(new StandardPasswordEncoder("53cr3t"));
    }

passwordEncoder()方法可以接受Spring Security中PasswordEncoder接口的任意实现,Spring Security的加密模块包括了三个这样的实现:BCryptPasswordEncoder、NoOpPasswordEncoder和StandardPasswordEncoder

如果内置的实现无法满足需求时,可以提供自定义实现PasswordEncoder接口

    public interface PasswordEncoder{
        String encode(CharSequence rawPassword);
        boolean matches(CharSequence rawPassword, String encodedPassword);
    }

基于LDAP进行认证

为了让Spring Security使用基于LDAP的认证,可以使用ldapAuthentication()方法

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
            .ldapAuthentication()
                .userSearchFilter("(uid = {0})")·
                .groupSearchFilter("member = {0}");
    }

userSearchFilter()和groupSearchFilter()用来为基础LDAP查询提供过滤条件,他们分别用于搜索用户和组,默认用户和组的基础查询都是空的,搜索会在LDAP层级结构的根开始,可以通过如下方式改变默认行为

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
            .ldapAuthentication()
            .userSearchBase("ou=pople") //指定从名为people的组织单元下搜索
            .userSearchFilter("(uid={0})")
            .groupSearchBase("ou=groups") //指定从名为groups的组织单元下搜索
            .groupSearchFilter("member={0}")
    }

配置密钥比对

基于LDAP进行认证的默认策略是进行绑定操作,直接通过LDAP服务器认证用户。另一种方式是进行比对操作,需要将输入密码发送到LDAP目录上,并要求服务器将这个密码和用户密码进行比对。通过密码比对进行认证

    @Override
    protected void configure(AuthenticationManagerBuilder auth){
        auth
            .ldapAuthentication()
                .userSearchBase("ou=people")
                .userSearchFilter("(uid={0})")
                .groupSearchBase("ou=groups")
                .groupSearchFilter("member={0}")
                .passwordCompare();
    }

默认情况下,登录表单中提供的密码会与用户LDAP条目中的userPassword属性进行比对,如果密码保存在不同的属性中,可以通过passwordAttribute()方法来声明密码属性的名称

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .userSearchBase("ou=people")
                .userSearchFilter("(uid = {0})")
                .groupSearchBase("ou=groups")
                .groupSearchFilter("member = {0}")
                .passwordCompare()
                .passwordEncoder(new Md5PasswordEncoder())
                .passwordAttribute("passcode");
    }

引用远程LDAP服务器

默认情况下Spring Security的LDAP认证假设LDAP服务器监听本机33389端口。我们也可以通过contextSource()配置远程LDAP服务器

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .userSearchBase("ou=people")
                .userSearchFilter("(uid = {0})")
                .groupSearchBase("ou = gourps")
                .groupSearchFilter("member = {0}")
                .contextSource()
                    .url("ldap://habuma.com:389/dc=habuma,dc=com")
    }

配置自定义用户服务

我们需要认证的用户数据可能存储在非关系型数据库中,这种情况下我们需要提供一个自定义的UserDetailsService接口实现

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

我们所要做的就是实现loadUserByUsername()方法,根据给定的用户名来查找用户

    public class SpitterUserService implements UserDetailsService{
        private final SpitterRepository spitterRepository;

        public SpitterUserService(SpitterRepository spitterRepository){
            this.spitterRepository = spitterRepository;
        }

        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
            Spitter spitter = spitterRepository.findByUsername(username);
            if(spitter != null){
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                authorities.add(new SimpleGrantedAuthority("ROLE_SPITTER"));
                return new User(
                    spitter.getUsername(),
                    spitter.getPassword(),
                    authorities
                );
            }
            throw new UsernameNotFoundException("User: " + username + " not found");
        }
    }

为了使用SpitterUserService来认证用户,可以通过userDetailsService()方法设置到安全配置中。userDetailsService()方法会配置一个用户存储。另一种方案是实现UserDetails,这样就可以直接返回实现UserDetails的对象

    @Authowired
    SpitterRepository spitterRepository;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(new SpitterUserService(spitterRepository));
    }

拦截请求

适当的安全性控制是必要的。对每个请求进行细粒度安全性控制的关键在于重载configure(HttpSecurity)方法

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
            .authorizeRequests()
                .antMatchers("/spitters/me").authenticated()
                .antMatchers("HttpMethod.POST", "/spittles").authenticated()
                .anyRequest().permitAll();
    }

HttpSecurity对象可以在多个方面配置HTTP的安全性,通过调用authorizeRequests()方法返回的对象的方法配置请求级别的安全性细节:

  • antMatchers():路径支持Ant风格的通配符,也可以在方法中指定多个路径

  • regexMatchers():接受正则表达式来定义请求路径

  • authenticated():要求执行该请求时,必须已经登陆了应用,如果用户没有认证,Spring Security的Filter将会捕获该请求,并将用户重定向到应用的登陆页面

  • permitAll():允许请求没有任何的安全限制

  • access(String):如果给定的SpEL表达式计算结果为true,就允许访问

  • anonyMous():允许匿名用户访问

  • denyAll():无条件拒绝所有访问

  • fullyAuthenticated():如果用户是完整认证,而不是通过Rememer-me功能认证,就允许访问

  • hasAnyAuthority(String…):如果用户具备给定权限中的某一个的话,就允许访问

  • hasAnyRole(String…):如果用户具备给定角色中的某一个,就允许访问

  • hasAuthority(String):如果用户具备给定权限,就允许访问

  • hasIpAddress(String):如果请求来自给定IP地址,就允许访问

  • hasRole(String):如果用户具备给定角色,就允许访问,自定使用“ROLE_”前缀

  • not():对其他访问方法的结果求反

  • rememberMe():如果用户是通过remember-me功能进行认证的,就允许访问
    这些规则会按照给定的顺序发挥作用,因此我们需要将最为具体的请求路径放在前面,最不具体的路径放在后面,不然不具体的路径配置将会覆盖更为具体的路径

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

借助access()方法我们可以将SpEL作为声明式访问限制的一种方法,Spring Security支持的SpEL表达式:

  • authentication:用户的认证对象

  • denyAll:结果始终为false

  • hasAnyRole(list of roles):如果用户被授予了列表中任意的指定角色,结果为true

  • hasRole(role):如果用户被授予了指定的角色,结果为true

  • hasIpAddress(IP Address):如果请求来自指定的IP,结果为true

  • isAnonymous():如果当前用户为匿名用户,结果为true

  • isAuthenticated():如果当前用户进行了认证,结果为true

  • isFullyAuthenticated():如果当前用户进行了完整认证,而不是Remember-me功能进行认证,结果为true

  • isRememberMe():如果当前用户是通过Remember-me自动认证,结果为true

  • permitAll:结果始终为true

  • principal:用户的principal对象

access()方法使用示例::

.antMatchers("/spitter/me")
    .access("hasRole('ROLE_SPITTER') and hasIpAddress('192.168.1.2')")

强制通道的安全性

通过requiresChannel()方法,可以为各种URL模式声明所要求的通道:

  • requiresSecure():会自动把请求重定向到HTTPS上

  • requiresInsecure():会把请求重定向到不安全的HTTP通道上

示例::

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
            .authorizeRequests()
                .antMatchers("/spitter/me").hasRole("SPITTER")
                .antMatchers(HttpMethod.POST, "/spittles").hasRole("SPITTER")
                .anyRequest().permitAll()
            .and()
            .requiresChannel()
                .antMatchers("/spitter/form").requiresSecure()
                .antMatchers("/").requiresInecure();

    }

防止跨站请求伪造

从Spring Security 3.2开始,默认开启CSRF防护,通过一个同步token的方式来实现CSRF防护功能,它会拦截状态变化的请求并检查CSRF token,如果请求中不包含CSRF token或者token不能与服务器端的token相匹配,请求将会失败,并抛出CsrfException异常。Spring Security简化了将token放入请求属性中这一任务,如果使用Thymeleaf作为页面模版,只要标签的action属性添加了Thymeleaf命名空间前缀,那么就会自动生成一个“_csrf”隐藏域

    <form method = "POST" th:action = "@{/spittles}">
        ...
    </form>

使用JSP作为页面模板

    <input type = "hidden"
            name = "${_csrf.parameterName}"
            value = "${_csrf.token}" />

使用Spring表单绑定标签,sf:form 标签会自动为我们添加隐藏的SCRF token标签

关闭CSRF防护功能

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
            ...
            .csrf()
                .disable(); //禁止CSRF防护功能
    }

认证用户

启用HTTP Basic认证

HTTP Basic认证会直接通过HTTP请求本身,对要访问应用程序的用户进行认证。本质上这是一个HTTP 401响应,表明必须要在请求中包含一个用户名和密码,在REST客户端向它使用的服务端进行认证的场景中,比较合适

  • httpBasic():开启HTTP Basic认证

  • realmName():指定域

示例

    @Override
    protected void configure(HttpSecurity http) throw Exception{
        http
            .formLogin()
                .loginPage("/login")
            .and()
            .httpBasic()
                .realmName("Spittr")
    }

启用Remember-me功能

Spring Security通过rememberMe()方法开启Remember-me功能

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
            .fromLogin()
                .loginPage("/login")
            .and()
            .rememberMe()
                .tokenValiditySeconds(2419200) //设置token有效时间
                .key("spittrKey"); //设置私钥名为spittrKey,默认为SpringSecured
    }

默认情况下这个功能是通过在cookie中存储一个token完成,默认两周内有效,存储在cookie中的token包含用户名、密码、过期时间和一个私钥。

Remember-me功能开启后,我们需要一种方式来让用户表明希望应用程序能够记住他们,为了实现这一点,需要请求必须包含一个名为Remember-me的参数

    <input id = "remember_me" name = "remember-me" type = "checkbox"/>
    <label for = "remember_me" class = "inline">Remember me</label>

退出

退出功能是通过Servlet容器中的Filter实现的,这个Filter会拦截针对“/logout”的请求。Spring Security的LogoutFilter会拦截处理发起“/logout”的请求,用户会退出应用,所有的Remember-me token都会被清除,用户浏览器将重定向到“/login?logout”,允许用户再次登录

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

可以配置用户退出将页面重定向到其它页面

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
            .formLogin()
                .loginPage("/login")
            .and()
            .logout()
                .logouSuccessUrl("/")
    }

通过logoutUrl()重写默认LogoutFilter拦截器路径

    .logout()
        .logoutSuccessUrl("/")
        .logoutUrl("signout")

springboot对security的支持

Spring Boot针对Spring Security的自动配置在org.springframework.boot.autoconfigure.security包中。主要通过SecurityAutoConfiguration和SecurityProperties来完成配置。SecurityAutoConfiguration导入SpringBootWebSecurityConfiguration中的配置,在SpringBootWebSecurityConfigoration配置中,获得如下的自动配置:

  • 自动配置了一个内存中的用户,账号为user,密码在程序启动时出现

  • 忽略/css/、/js/、/images/和//favicon.ico等静态文件的拦截

  • 自动配置的securityFilterchainRegistration的Bean

SecurityProperties使用以“security”为前缀的属性配置Spring Security相关的配置

    security.user.name=user #内存中的用户,默认是账号为user
    security.user.password= #默认用户的密码
    security.user.role=USER #默认用户的角色
    security.require-ssl=false #是否需要ssl支持
    security.enable-csrf=false #是否开启“跨站请求伪造”支持,默认关闭
    security.basic.enabled=true
    security.basic.realm=Spring
    security.basic.path=
    security.basic.authorize-mode=
    security.filter-order=0
    security.headers.xss=false
    security.headers.cache=false
    security.headers.frame=false
    security.headers.content-type=false
    security.headers.hsts=all
    security.sessions=stateless
    security.ignore= #用逗号隔开的无须拦截的路径

通过继承WebSecurityConfigurerAdapter类,可扩展自己的配置

    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    }

实战

新建Spring Boot项目,依赖为JPA、Security、Thymeleaf

  1. 添加依赖

  2. 添加配置文件application.properties::

    spring.datasource.driverclassName=
    spring.datasource.url=
    spring.datasource.username=
    spring.datasource.password=
    logging.level.org.springframwork.security= INFO
    spring.thymeleaf.cache=false
    spring.jpa.hibernate.ddl-auto= update
    spring.jpa.show-sql= true
  1. 用户和角色::
    /**
    *实现UserDetails接口
    *
    */
    @Entity
    public class SysUser implements UserDetails{
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue
        private Long id;
        private String username;
        private String password;
        @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
        private List<SysRole> roles;

        /**
        *重写getAuthorities()方法,将角色作为权限
        *
        */
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities(){
            List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
            List<SysRole> roles = this.roles;
            for(SysRole role:roles){
                auths.add(new SimpleGrantedAuthority(role.getName()));
            }
            return auths;
        }

        @Override
        public boolean isAccountNonExpired(){
            return true;
        }

        @Override
        public boolean isAccountNonLocked(){
            return true;
        }

        @Override
        public boolean isCredentialsNonExpired(){
            return true;
        }

        @Override
        public boolean isEnabled(){
            return true;
        }

        //省略getter、setter方法
    }


    @Entity
    public class SysRole{
        @ID
        @GeneratedValue
        private Long id;

        private String name;
        //省略getter、setter方法
    }

    /**
    *传值对象
    *
    */
    public class Msg{
        private String title;
        private String conten;
        private String etraInfo;
        public Msg(String title, String content, String etraInfo){
            super();
            this.title = title;
            this.content = content;
            this .etraInfo = etraInfo;
        }
        //省略getter、setter方法
    }
  1. 数据访问
    public interface SysUserRepository extends JpaRepository<SysUser, Long>{
        SysUser findByUsername(String username);
    }
  1. 自定义UserDetailsService
    /**
    *自定义实现UserDetailsService接口
    *
    */
    public class CustomUserService implements UserDetailsService{
        @Autowired
        SysUserRepository userRepository;

        /**
        *重写loadUserByUsername方法获得用户
        *
        */
        @Override
        public UserDetails loadUserByUsername(String username){
            SysUser user = userRepository.findByUsername(username);
            if(user == null){
                throw new UsernameNotFoundException("用户名不存在")
            }
            return user;
        }
    }
  1. Spring MVC配置
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter{
        @Override
        public void addViewControllers(ViewContollerRegistry registry){
            registry.addViewController("/login").setViewName("login");
        }
    }
  1. Spring Security配置
    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
        @Bean
        UserDetailsService customUesrService(){
            return new CustomUserService();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            auth.userDetailsService(customUserService());
        }

        @Override
        protected void configure(HttpSecutity http) throws Exception{
            http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                        .loginPage("/login")
                        .failureUrl("/login?error")
                        .permitAll() //定制登录行为,登录页面可任意访问
                    .and()
                    .logout().permitAll(); //定制注销行为,注销请求可任意访问
        }
    }
1.全基因组重测序数据分析介绍 二代测序原理及fastq数据解读、全基因组重测序数据分析内容 阅读详情

相关推荐

【训练】Qwen2.5VL 多机多卡 Grounding Box定位

之前的相关文章:【深度学习】LLaMA-Factory微调sft Qwen2-VL进行印章识别使用LLaMA-Factory微调sft Qwen2-VL-7B-Instruct构建最新的LLaMA-Factory镜像。

q742971636的博客 2585

深入理解Spring Security授权机制原理

原创/朱季谦 在Spring Security权限框架里,若要对后端http接口实现权限授权控制,有两种实现方式。 一、一种是基于注解方法级的鉴权,其中,注解方式又有@Secured和@PreAuthorize两种。 @Secured如: 1 @PostMapping("/test") 2 @Secured({WebResRole.ROLE_PEOPLE_W}) 3 public void test(){ 4 ...... 5 return null; 6 }

朱季谦 1560

Ubuntu22环境下Xinference与RAGFLOW集成:构建高效rerank模型服务【实战指南】

本文详细介绍了在Ubuntu22.04系统上,通过部署Xinference模型推理服务来加载bge-reranker-base等rerank模型,并将其与RAGFLOW框架集成的完整实战指南。该方案实现了模型服务的解耦与灵活管理,有效提升RAG系统的检索精度与答案相关性,并提供了从环境配置、服务启动、网络连接到性能调优及常见问题排查的全流程解决方案。

pluto的博客 501

SingelSignOn之Security配置类

1.使用SpringSecurity安全框架定义Security配置类(配置认证规则) (1)加密并重写configure方法: 此方法为http请求配置方法,可以在此方法中配置: 1)哪些资源放行(不用登录即可访问),假如不做任何配置默认所有资源都匿名访问 2)哪些资源必须认证(登录)后才可访问。 @Bean //密码加密对象 public PasswordEncoder passwordEncoder(){ //底层调用boolean matches(C..

weixin_61863480的博客 2743

华为私有云HCS 8.1.1实战:从镜像制作到云主机发放全流程指南

本文详细解析了华为私有云HCS 8.1.1从镜像制作到云主机发放的全流程实战指南。内容涵盖制作标准化QCOW2镜像、配置云主机规格与主机组、规划外部网络,以及在运营面为租户初始化资源、配置审批流与产品目录。最后,通过用户视角演示了从创建VPC网络到申请、审批并最终绑定EIP访问云主机的完整操作步骤,为运维人员和架构师提供了一套清晰、可落地的HCS部署与管理实践方案。

weixin_29305313的博客 1129

OpenMMLab实战指南:从环境搭建到首个检测模型运行

本文是一份详细的OpenMMLab实战指南,重点介绍了如何从零开始搭建环境并运行首个目标检测模型。内容涵盖Miniconda环境配置、PyTorch与CUDA版本匹配、使用MIM工具安装MMCV和MMDetection的核心步骤,并通过RTMDet-tiny模型演示了完整的推理流程,帮助开发者高效入门这一计算机视觉开源算法体系。

weixin_28678151的博客 160

HttpSecurity初步理解

关于用户身份验证的相关知识请参看这个链接,本文只对HttpSecurity做以简单介绍。 Spring Security是一个强大的、可根据需求高度自定义的用户认证和访问控制框架。Spring Security怎么保证所有向Spring application发送请求的用户必须先通过认证;怎么保证它自己支持用户通过表单的方式进行认证。解决的办法是Spring Security中有个WebSec...

骑着蜗牛向前跑的博客 2万+

【MATLAB代码】UKF组合导航例程,15维状态量、3维观测量。附完整的代码,有中文注释、误差输出图像

摘要 本文提出了一种基于15维误差状态模型的UKF组合导航算法,实现了三维位置、速度和姿态的高精度估计。算法采用严格的误差状态模型,包含位置(3)、速度(3)、姿态(3)、陀螺偏差(3)和加速度计偏差(3)共15个状态量,通过3维GNSS位置观测进行校正。仿真结果表明,相比纯IMU积分,UKF算法能有效抑制误差积累,显著提高导航精度。文中提供了完整的MATLAB源代码,可直接运行并复现三维轨迹对比、位置/速度曲线及误差分析结果。

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 312

HttpSecurity常用方法详解

requestMatchers() 取得RequestMatcherConfigurer对象并配置允许过滤的路由; 如requestMatchers().anyRequest()等同于http.authorizeRequests().anyRequest().access(“permitAll”); 如下面两个例子: @Override public void configure(HttpSecurity http) throws Exception { //只允许路由由test开头的需要

qq_30641461的博客 1万+

AI测试干货:Claude Code Skill 从入门到精通

本文介绍了Claude Code Skill功能如何解决AI重复工作问题。传统提示词方式需要人工复制粘贴,而Skill功能通过建立AI工作记忆库实现智能触发和分层加载。Skill包含工作指令、文档和资源,能自动执行任务。文章以API测试用例生成为例,展示了Skill的创建流程和结构化设计,包括测试框架、覆盖场景和输出格式,显著提升测试工程师的工作效率。

blues_C的博客 2445

Windows版TASSEL5的下载及安装

TASSEL5是一款用于研究表型和基因型关系的软件,由美国康奈尔大学Buckler实验室所研发。,选择Windows环境安装包下载并安装。1.安装成功后TASSEL5界面。

沉香best的博客 8188

Spring Security(二)

在上一节我们完成了最基本的security配置,下面我们了解下如何配置用户信息,包括内存签名服务,数据库签名服务和自定义签名服务三种。 首先,说下内存签名服务,顾名思义,就是将用户的相关信息放在内存中,一般用于项目初期的环境搭建验证。 @Configuration @EnableWebSecurity public class SecurityConfig extends W...

小乔美哒哒 399

js逆向第24例:FastMoss数据分析网站Fm-Sign加密字段破解

破解:FastMoss数据分析网站Fm-Sign加密字段。FastMoss主要是TikTok为主的大数据分析服务的一个网站

花臂不花Home 2154

AWS WAF保护Web应用程序

摘要:本文详细介绍了在AWS WAF中创建Web访问控制规则(WebACL)的完整步骤,主要包括:1)创建IPSet黑名单;2)配置WebACL并应用IP黑名单规则;3)扩展设置地理位置封禁规则;4)添加SQL注入、XSS攻击拦截规则;5)设置DDoS速率限制;6)最终在WebACL中查看所有规则并关联目标资源(如负载均衡器)。通过这些配置可以有效防护常见Web安全威胁,包括IP封禁、地理限制、SQL注入、XSS攻击和DDoS防护等。

qq_63010039的博客 1673

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

使用Spring Security保护 Web 应用程序

本指南将指导您完成使用受 Spring Security 保护的资源创建简单 Web 应用程序的过程。

jackiendsc的博客 164

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

使用 Spring Security 保护 Web 应用的安全

在 Web 应用开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一

1083

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Spring实战4(8)保护Web应用

后续补充

u012737025的博客 204

如何保护Web应用程序

虽然安全性是所有应用程序都需关心的方面,但是它对于Web应用程序组件尤为重要。不安全的Web应用程序使Web站点易受多种攻击,而且有些攻击仅仅需要一个Internet浏览器和少量相关知识即可。  Java 2 Enterprise Edition(J2EE)提供许多安全功能。了解何时以及如何使用这些功能是一件复杂的工作,而且易于出错。此外,J2EE的安全性无法满足许多Web应用程序开发人员的需

1161

南墙Web应用防火墙:保护您的Web应用安全

随着互联网的发展,Web应用越来越普遍,也越来越受到黑客攻击的威胁。为了保护Web应用的安全,我们需要引入一种强大的防火墙机制,即南墙Web应用防火墙。本文将详细介绍南墙Web应用防火墙的实现原理、相关步骤和代码片段。南墙Web应用防火墙是一种强大的安全机制,可以有效保护Web应用免受黑客攻击的威胁。通过实时监测和拦截机制,南墙Web应用防火墙能够及时发现并阻止潜在的攻击行为。希望本文能为您了解南墙Web应用防火墙的实现原理和相关步骤提供帮助。保护您的Web应用安全:南墙Web应用防火墙详解。

理论都是虚的,代码才是王道。 1235

全面解析Web应用防火墙如何保护核心应用

<br />全面解析Web应用防火墙如何保护核心应用<br />目前,利用网上随处可见的攻击软件,攻击者不需要对网络协议的深厚理解基础,即可完成诸如更换Web网站主页,盗取管理员密码,破坏网站数据等攻击。这些攻击过程中产生的网络层数据和正常数据没有什么区别,传统的防火墙对于这些攻击束手无策。 <br />由于针对Web站点的攻击行为越来越多,且更加难以控制,一些安全厂商,如将Citrix、Barracuda-NetContinuum、F5 Networks、Imperva和Protegrity,将在今后的几

zhiguo2010的专栏 552

安全的后端安全:保护Web应用的关键组件

1.背景介绍 后端安全性是Web应用程序的关键组件,因为它负责处理敏感数据和处理与用户交互的所有请求。然而,后端安全性通常被忽视,导致Web应用程序受到攻击。在本文中,我们将讨论后端安全性的重要性,以及如何保护Web应用程序的关键组件。 1.1 后端安全性的重要性 后端安全性是Web应用程序的基础,因为它涉及到数据保护、用户身份验证和授权、数据传输安全等方面。如果后端安全性不足,攻击者可以窃...

AI天才研究院 491

使用Spring Security保护Web应用

本文将详细介绍如何使用Spring Security保护Web应用,包括基本的配置、身份验证和授权、以及一些高级功能。本文详细介绍了如何使用Spring Security保护Web应用,包括基本配置、自定义登录页面、基于角色的访问控制、方法级别的安全控制、使用数据库进行身份验证以及启用HTTPS等。Spring Security默认提供了一个简单的登录页面,但在实际项目中,我们通常需要自定义登录页面。大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!

技术研究中心 361

数据保护在Web3应用中的重要性及其实现

在这个信息爆炸的时代,Web3 以其去中心化、用户主权和数据隐私保护的特点,成为了互联网发展的新趋势。Web3 不仅仅是技术的革新,更是对用户隐私和数据安全的一种承诺。本文将深入探讨数据保护在 Web3 应用中的重要性,并介绍其实现方式,以确保用户在这个新的数字世界中能够安心地遨游。

dd8989089的博客 856

使用Spring Security保护web应用安全

转载地址:http://www.oschina.net/question/12_13626 在 Web 应用开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问 题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应

z1074907546的博客 2726

Java Web应用软件保护方法

1 代码混淆概述目前针对Java源文件方法主要有以下几种方法:本地编译技术、数字水印技术、ClassLoader加密技术以及代码混淆技术。Java本地编译是指将Java应用程序编译成本地应用程序,如Windows平台下名为exe的应用程序。通过java虚拟机将由源代码生成Java类文件,再将类文件编译成可执行文件。用该技术生成的本地应用程序是二进制格式的可执行文件,但该方法牺牲了Java...

217

web应用程序安全性测试_保护Web应用程序安全的8种做法

web应用程序安全性测试When it comes to application security, in addition to securing your hardware and platform, you also need to write your code securely. This article will explain how to keep your application...

culi3182的博客 762
上一篇: OAuth令牌
下一篇: Spring OAuth2
炒栗子不加糖
博客等级 码龄10年 68粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值