SpringMvc in Action——保护Web应用

Spring Security简介

Spring Security 是为基于Spring的应用程序提供声明式安全保护的安全性框架。Spring Security提供了完整的安全性解决方案,它能够在Web请求级别和方法调用级别处理身份认证和授权。因为基于Spring框架,所以Spring Security充分利用了依赖注入DI和面向切面AOP的技术。

理解Spring Security的模块
在这里插入图片描述
应用程序的类路径下至少要包含Core和Configuration这两个模块。Spring Security经常被用于保护Web应用。同时我们可能也会用到Spring Security的JSP标签库,所以我们也要讲Tag Library添加进来。

过滤Web请求
Spring Security借助一系列Servlet Filter来提供各种安全性功能。你可能会想,这是否意味着我们需要在web.xml或者WebApplicationInitializer中配置多个Filter呢?实际上,我们只需要配置一个Filter就行。
DelegatingFilterProxy是一个特殊的Servlet Filter,它本身所做的工作并不多。只是将工作委托给一个javax.servlet.Filter实现类。
在这里插入图片描述
我们这里用java的方式来配置DelegatingFilterProxy,我们所需要做的就是创建一个扩展的新类:(再次更新pom.xml)

package spittr.config;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {
}

AbstractSecurityWebApplicationInitializer也是实现了WebApplicationInitializer,因此Spring会发现它,并用它在Web容器中注册DelegatingFilterProxy
这个代理会拦截发往应用中的请求,并将请求委托给ID为springSecurityFilterChain bean。
springSecurityFilterChain本身是另一个特殊的Filter,它也被称为FilterChainProxy。它可以链接一个或多个Filter。

编写简单的安全性配置

package spittr.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

@EnableWebSecurity注解将会启用Web安全功能,但他本身并没有什么用处,Spring Security必须配置在一个实现了WebSecurityConfigurerAdapter里面才会起作用。

@EnableWebSecurity可以启动任意Web应用的安全性功能,不过如果你的应用碰巧是使用SpringMVC开发的,那么就应该考虑使用@EnableWebMvcSecurity替代它。(貌似已经弃用!)

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

尽管不是严格的,但是我们可能希望指定Web安全的细节,这样重载WebSecurityConfigurerAdapter 中的一个或多个方法实现:
在这里插入图片描述
我们现在默认的configure()方法是这样的:

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

这个默认配置制定了该如何保护HTTP请求,以及客户端认证用户的方案,通过调用authorizeRequests()和anyRequest().anthenticated()就会要求所有进入应用的HTTP请求都要进行认证。它也配置支持基于表单的登录formLogin()以及HTTP Basic方式的认证httpBasic()

为了让Spring Security 满足我们应用的需求,还需要再添加一点配置。具体来讲,我们需要:

  • 配置用户存储
  • 指定哪些请求需要认证,哪些不需要,以及所需要的权限
  • 提供一个自定义的登录页面,替代原来简单的默认登录页

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

这个标题有点难以理解,我们这样说:有一家饭店,我们会提前预定。但当我们去的时候,告诉服务员我们的名字,但遗憾的是,没有我们的预定记录!
服务员说,没有预定名单,事实上根本不存在这个预定名单。
这就是我们应用程序的现状。我们没办法进入应用,因为安全名单不存在。因为缺少用户存储。
好消息是,我们借助Spring Security的java配置,很容易配置一个或多个数据存储方案。

使用基于内存的用户存储
重载configure方法,并使用两个用户来配置内存用户存储。

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER")
                .and()
                .withUser("admin").password("password").roles("USER","ADMIN");
    }
}

AuthenticationManagerBuilder使用构造者风格的结构构建认证配置,通过简单调用.inMemoryAuthentication()来启用内存用户存储。
我们添加了两个用户“user”和“admin”,密码均为“password”。“user”具有USER角色,而“admin”具有USER和ADMIN两个角色。and将多个用户的配置连接起来。

基于数据库表进行认证
用户数据常常会存储在数据库中,并通过JDBC进行访问,为了配置Spring Security使用以JDBC为支撑的用户存储,我们可以使用jdbcAuthentication()方法:

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

    }

尽管这些配置能够运行,但是它对我们的数据库模式有要求,它默认运行下面的代码片段:
在这里插入图片描述
如果你数据库里有这些表,并且表结构相同,那我没有意见。
但有些时候,你数据库里定义和填充的不满足这些表,那么,我们可以按照如下的方式配置自己的查询:

    @Autowired
    DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
                .jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(
                        "select username,password,true from Spitter where username =?"
                )
                .authoritiesByUsernameQuery(
                        "select username,'USER' from Spitter where username=?"
                );

    }

很多时候,我们希望密码保密。所以需要把明文转为密文,我们需要借助passwordEncoder()方法指定一个密码转码器(encoder):

auth
                .jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(
                        "select username,password,true from Spitter where username =?"
                )
                .authoritiesByUsernameQuery(
                        "select username,'USER' from Spitter where username=?"
                )
                .passwordEncoder(new StandardPasswordEncoder("53cr3t"));

上面的代码使用了StandardPasswordEncoder,当然加密方式可以自定义实现,只需要实现PasswordEncoder接口即可。

基于LDAP进行认证
暂时用不到,暂略。

拦截请求

暂略

认证用户

暂略

保护视图

暂略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值