Why SpringSecurity?

在 Web 应用开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,因而需要更多的开发时间,影响应用的发布进程。

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。

MAVEN依赖

由于Spring Boot提供Maven BOM来管理依赖版本,因此无需指定版本。

<dependencies>
    <!-- ... other dependency elements ... -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

开源项目

以下代码已经发布在spring-cloud-study-security项目,可以直接下载使用。

核心代码


CustomFromLoginFilter

自定义表单登陆过滤:

  1. 读取页面穿过来的username和password的参数值
  2. 校验账号密码是否通过,不通过则报错
  3. 通过则授予USER权限
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义表单登录
 * @author zhengkai.blog.csdn.net
 */
public class CustomFromLoginFilter extends AbstractAuthenticationProcessingFilter {

    CustomFromLoginFilter(String defaultFilterProcessesUrl) {
        super(new AntPathRequestMatcher(defaultFilterProcessesUrl, HttpMethod.POST.name()));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
    	//读取页面穿过来的username和password
        String username = httpServletRequest.getParameter("username");
        String password = httpServletRequest.getParameter("password");
        //校验账号密码是否通过
        customCheck(username, password);
        //授予USER权限
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        simpleGrantedAuthorities.add(new SimpleGrantedAuthority("USER"));
        return new UsernamePasswordAuthenticationToken(username, password, simpleGrantedAuthorities);
    }

    private void customCheck(String username, String password){
    	//校验用户名为user密码为pass
        if (!("user".equals(username) && "pass".equals(password))){
            throw new RuntimeException("用户名或密码错误!");
        }

    }

}

WebSecurityConfig

Security配置:

  • .antMatchers("/login","/index","/logout").permitAll(),设置这些路径无需授权允许访问。
  • .formLogin().successForwardUrl("/user/list"),设置支持表单登陆,登陆成功后跳转到user/list的url路径
  • http.addFilterAt(customFromLoginFilter(), UsernamePasswordAuthenticationFilter.class);设置自定义过滤器,类型为账号密码授权过滤器。
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

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

        http.addFilterAt(customFromLoginFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 自定义认证过滤器
     */
    private CustomFromLoginFilter customFromLoginFilter() {
        return new CustomFromLoginFilter("/login");
    }

}

UserController

这里需要设置几个页面:

  • index默认页面,不需要授权,可以点击登陆
  • login登陆页面,不需要授权,进行登陆
  • user/list需要授权才可访问页面,必须登陆
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RestController
public class UserController {

	@GetMapping("index")
	public ModelAndView  index(){
		return new ModelAndView("index");
	}
	@GetMapping("login")
	public ModelAndView  login(String error){
		return new ModelAndView("login").addObject("error",error);
	}

	@GetMapping("user/list")
	public ModelAndView  userList(){
		return new ModelAndView("user-list");
	}
}

HTML页面

index.html

<h1>Index Html</h1>
<p>for security check.please <a href="${request.contextPath}/login">login</a></p>

login.html

<h1>Login Page</h1>
<form method="post" action="${request.contextPath}/login">
    <input id="username" name="username" placeholder="username" type="text">
    <input id="password" name="password" placeholder="password" type="password">
    <button type="submit">Login</button>
</form>

user-list.html

<h1>User List | Security Page</h1>
<p>U r under security state if u can see the page</p>

效果演示

springsecurity自定义grant_type根据Ukey授权 springsecurity自定义认证_spring security 自定义