Spring Security 簡單實現使用者登陸
阿新 • • 發佈:2019-01-14
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
密碼為12345
的ADMIN
許可權使用者,此例未將賬號資訊儲存到持久層內。
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.html
將javascript: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