Spring Security 入门

Spring Projects 简介

从配置到安全性,Web应用到大数据 - 无论您的应用程序的基础架构需求如何,都有一个Spring Project来帮助您构建它。
从小处着手,根据需要使用 - Spring是通过设计模块化的。
https://spring.io/projects
QQ20180409-101459@2x

Spring Security 简介

Spring Security是一个强大且高度可定制的身份验证和访问控制框架。
这是保护基于Spring的应用程序的事实标准。
Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。
与所有Spring项目一样,Spring Security的真正实力在于如何轻松扩展以满足自定义需求

Spring Security 功能

全面和可扩展的支持认证和授权
防止会话固定,点击劫持,跨站点请求伪造等攻击
Servlet API集成
与Spring Web MVC的可选集成
多得多…

Spring Boot项目集成Spring Security

现在有一个spring boot web项目,只有一个非常简单控制器:

@Controller
public class MainController {

	@RequestMapping("/")
	public String root() {
		return "redirect:/index";
	}

	@RequestMapping("/index")
	public String index() {
		return "index";
	}

	@RequestMapping("/user/index")
	public String userIndex() {
		return "user/index";
	}

}

有三个主要请求路径
/ 访问根路径跳转
/index 网站首页
/user/index 用户的首页

接下来接入Spring Security,这里定义一下用户及角色:
用户名为“user”的用户拥有角色“USER”,有角色“USER”的用户才有权限访问/user/index

新建类SecurityConfig

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/css/**", "/index").permitAll()//与/ css / **和/ index匹配的请求是完全可访问的
                .antMatchers("/user/**").hasRole("USER")//与/ user / **匹配的请求需要用户进行身份验证,并且必须与USER角色关联
                .and()
                .formLogin()
                .loginPage("/login").failureUrl("/login-error") .permitAll();;//使用自定义登录页面和失败url启用基于表单的身份验证
    }

    /**
     * The name of the configureGlobal method is not important.
     * However, it is important to only configure AuthenticationManagerBuilder
     * in a class annotated with either @EnableWebSecurity,
     * @EnableGlobalMethodSecurity, or @EnableGlobalAuthentication.
     * Doing otherwise has unpredictable results.
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER");
    }
}
  • .loginPage("/login")包含以下过程:
    • 当需要认证时,将浏览器重定向到/登录
    • 我们负责在/ login请求时呈现登录页面
    • 当认证尝试失败时,将浏览器重定向到/ login?错误(因为我们没有另外指定)
    • 当/ login?错误被请求时,我们负责渲染失败页面
    • 当我们成功注销时,将浏览器重定向到/ login?注销(因为我们没有另外指定)
    • 我们负责在请求/ login?注销时呈现注销确认页面
  • .antMatchers("/css/**", "/index").permitAll()这允许任何人访问以/ css开头的URL 。由于这是我们的CSS,类似的,我们应该让所有的静态资源/js、/images 等都可以被任何人查看。
  • 方法formLogin().permitAll()声明指示Spring Security允许与之关联的URL(即/login和/login-error)可任意访问。
  • 授予对formLogin()URL的访问权限并未默认完成,因为Spring Security需要对允许和不允许的内容作出某些假设。为了安全起见,最好确保授予资源访问权限是明确的。

修改MainController为:

@Controller
public class MainController {

	@RequestMapping("/")
	public String root() {
		return "redirect:/index";
	}

	@RequestMapping("/index")
	public String index() {
		return "index";
	}

	@RequestMapping("/user/index")
	public String userIndex() {
		return "user/index";
	}

	@RequestMapping(value = "/login")
	public String login() {
		return "login";
	}

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String postLogin() {
		// TODO Enable form login with Spring Security (trigger error for now)
		return "redirect:/login-error";
	}

	@RequestMapping("/login-error")
	public String loginError(Model model) {
		model.addAttribute("loginError", true);
		return "login";
	}

}

网站主页index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <title>Hello Spring Security</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
    Logged in user: <span sec:authentication="name"></span> |
    Roles: <span sec:authentication="principal.authorities"></span>
    <div>
        <form action="#" th:action="@{/logout}" method="post">
            <input type="submit" value="Logout" />
        </form>
    </div>
</div>
<h1>Hello Spring Security</h1>
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
<ul>
    <li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li>
</ul>
</body>
</html>
  • /logout是Spring Security提供的,无需我们处理

登录页面login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Login page</title>
        <meta charset="utf-8" />
        <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
	</head>
    <body>
        <h1>Login page</h1>
        <p>Example user: user / password</p>
        <p th:if="${loginError}" class="error">Wrong user or password</p>
        <form th:action="@{/login}" method="post">
            <label for="username">Username</label>:
            <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
            <label for="password">Password</label>:
            <input type="password" id="password" name="password" /> <br />
            <input type="submit" value="Log in" />
        </form>
        <p><a href="/index" th:href="@{/index}">Back to home page</a></p>
    </body>
</html>

  • 我们提交我们的用户名和密码的URL与我们的登录表单(即/login)相同,但使用POST而不是GET。
  • 当验证失败时,浏览器被重定向到/login-error,因此我们可以通过检测参数错误是否为非空来显示错误消息。
  • 当我们成功注销后,浏览器被重定向到/login?logout,因此我们可以通过检测参数注销是否为非空来显示注销成功消息。
  • 用户名应该存在于HTTP参数username
  • 密码应该存在于HTTP参数password
  • 不要显示关于验证失败原因的详细信息。例如,我们不希望显示用户不存在,因为这会告诉攻击者他们应该尝试使用不同的用户名。
  • Thymeleaf或Spring MVC taglib会自动将CSRF令牌添加到我们的表单中。如果我们使用其他模版引擎,我们也可以使用手动添加CSRF令牌<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

完整代码:https://github.com/toocruel/springProjectsStudy/tree/master/spring-security

效果
首页:
QQ20180408-141945@2x-1

点击secured pages 进去登录页:
QQ20180408-141958@2x-1

输入user password 进入用户主页:
QQ20180408-142017@2x-1

(全文完)

(转载本站文章请注明作者和出处 Spring Security 入门