Spring Security 简单实现用户登陆

Spring Security 实现用户登陆

本文仅介绍Spring Security的基本使用。

Spring Security简介

Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

  • 认证(Authentication):“认证”是建立主体(principal)的过程。“主体”通常是指可以在您的应用程序中执行操作的用户、设备或其他系统。
  • 授权(Authorization):或称为“访问控制(Access-control)”,“授权”是指决定是否允许主体在应用程序中执行操作。

身份验证技术主要有:

身份验证 . . .
HTTP BASIC 单点登陆
HTTP Digest Remember-Me
HTTP X.509 匿名身份验证
LDAP Run-as
基于表单的认证 JAAS
OpenID JavaEE容器认证

Spring Security 配置

完整工程

build.gradle

关键代码:

dependencies {
    //SpringBoot必要组件和测试组件
	implementation('org.springframework.boot:spring-boot-starter-web')
	testImplementation('org.springframework.boot:spring-boot-starter-test')
	//thymeleaf 模板引擎
	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	//Spring Data JPA 持久层支持
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	//Mysql 连接驱动
	compile('mysql:mysql-connector-java:8.0.11')
	//H2 内存数据库
	runtime('com.h2database:h2:1.4.193')
	//Spring Security 权限管理
	compile('org.springframework.boot:spring-boot-starter-security')
	//Thymeleaf Spring Security 对Thymeleaf的支持
	compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE')
}

完整代码:HERE

SecurityConfig.java

SecurityConfig.java为配置类,继承自org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter类。

用于自定义一些配置。

package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	/**
	 * 自定义权限配置
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().antMatchers("/css/**", "/js/**", "/fonts/**", "/index").permitAll()// 都可以访问
				.antMatchers("/users/**").hasRole("ADMIN")// 需要相应角色权限才能访问
				.and().formLogin()// 基于Form表单验证
				.loginPage("/login").failureUrl("/login-error");// 自定义登陆界面
		http.csrf().disable();// 禁用security的csrf功能
	}
	/**
	 * 用户认证
	 * 添加用户名为admin密码为12345的ADMIN权限用户
	 * @param auth
	 * @throws Exception
	 */
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication()// 认证信息储存在内存中
				.withUser("admin").password("12345").roles("ADMIN");
	}
}

这里注意:

http.csrf().disable();// 禁用security的csrf功能

这句是为了使RESTful正常使用。

这里设定了/css/**/js/**/fonts/**/index是都可以访问且不涉及权限的,但需要ADMIN账户才能访问。且登陆基于Form表单验证,登陆界面和登陆错误返回页面分别为/login/login-error

并将账号信息注入到内存中,即用户名为admin密码为12345ADMIN权限用户,此例未将账号信息存储到持久层内。

MainController.java

@Controller
public class MainController {
	@GetMapping("/")
	public String root() {
		return "redirect:/index";
	}
	@GetMapping("/index")
	public String index() {
		return "index";
	}
	@GetMapping("/login")
	public String login() {
		return "login";
	}
	@GetMapping("/login-error")
	public String loginError(Model model) {
		model.addAttribute("loginError",true);
		model.addAttribute("errorMsg", "登陆失败,用户名或密码错误!");
		return "login";
	}
}

完整代码:HERE

前端框架

fragments部分

header.html会根据用户是否登陆显示不同的内容。

<!-- 登陆判断 -->
<div sec:authorize="isAuthenticated()" class="row">
	<ul class="nav navbar-nav navbar-right">
		<li><a><span class="nav-link" sec:authentication="name"></span></a></li>
		<li><a href="javascript:doPost()" class="btn btn-outline-success">退出<span class="sr-only">(current)</span></a></li>
	</ul>
</div>
<div sec:authorize="isAnonymous()">
	<ul class="nav navbar-nav navbar-right">
		<li><a href="/login" th:href="@{~/login}" class="btn btn-outline-success">登陆</a></li>
	</ul>
</div>

footer.htmljavascript:doPost()函数也根据用户是否登陆显示出来。

<div sec:authorize="isAuthenticated()">
	<script>
		function doPost() {  // 登出函数
			var myForm = document.createElement("form");     
			myForm.method = "post";
			myForm.action = "/logout";    
			document.body.appendChild(myForm);   
			myForm.submit(); 
			document.body.removeChild(myForm);  // 提交后移除创建的form
		}
	</script>
</div>

此处用JavaScript创建一个表单,要想正常工作须在前面配置文件初加上代码:

http.csrf().disable();// 禁用security的csrf功能

来禁用security的csrf功能。

templates模板

index.html根据用户是否登陆显示不同的页面。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head th:replace="~{fragments/header::header}">
</head>
<body>
	<div class="container">
		<div class="jumbotron">
			<div sec:authorize="isAuthenticated()">
				<p>已有用户登陆</p>
				<p>
					登陆的用户为:<span sec:authentication="name"></span>
				</p>
				<p>
					用户角色为:<span sec:authentication="principal.authorities"></span>
				</p>
			</div>
			<div sec:authorize="isAnonymous()">
				<p>未有用户登陆</p>
			</div>
		</div>
	</div>
	<div th:replace="~{fragments/footer::footer}"></div>
</body>
</html>

login.html则是根据一个form表单来提交账号密码。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head th:replace="~{fragments/header::header}">
</head>
<body>
	<!-- Page content -->
	<div class="container">
		<div class="jumbotron">
			<form th:action="@{~/login}" method="post">
				<h2>请登录</h2>
				<div class="form-group col-md-5">
					<label for="username" class="col-form-label">账号</label> <input
						type="text" class="form-control" id="username" name="username"
						maxlength="50" placeholder="请输入账号">
				</div>
				<div class="form-group col-md-5">
					<label for="password" class="col-form-label">密码</label> <input
						type="password" class="form-control" id="password" name="password"
						maxlength="30" placeholder="请输入密码">
				</div>
				<div class="form-group col-md-5">
					<button type="submit" class="btn btn-primary">登陆</button>
				</div>
				<div class="col-md-5" th:if="${loginError}">
					<p class="label-error" th:text="${errorMsg}"></p>
				</div>
			</form>
			<br><br><br><br><br><br>
		</div>
	</div>
	<div th:replace="~{fragments/footer::footer}"></div>
</body>
</html>

完成后界面:

未有用户登陆时

登陆界面

已有用户登陆

完整项目地址:HRER

猜你喜欢

转载自blog.csdn.net/SilenceSpeaks/article/details/86475806