SpringBoot +SpringSecurity+mysql 实现用户数据权限管理
通用用户数据权限sql建库 和初始化脚本:
/*
Navicat MySQL Data Transfer
Source Server : 192.168.1.73
Source Server Type : MySQL
Source Server Version : 80015
Source Host : 192.168.1.73:3306
Source Schema : boot-security
Target Server Type : MySQL
Target Server Version : 80015
File Encoding : 65001
Date: 15/07/2019 16:40:44
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for u_permission
-- ----------------------------
DROP TABLE IF EXISTS `u_permission`;
CREATE TABLE `u_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`url` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'url地址',
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'url描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_permission
-- ----------------------------
INSERT INTO `u_permission` VALUES (1, 'userInfo/userList', '用户管理');
INSERT INTO `u_permission` VALUES (2, 'userInfo/userAdd', '用户添加');
INSERT INTO `u_permission` VALUES (3, 'userInfo/userDel', '用户删除');
-- ----------------------------
-- Table structure for u_role
-- ----------------------------
DROP TABLE IF EXISTS `u_role`;
CREATE TABLE `u_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色名称',
`type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色类型',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_role
-- ----------------------------
INSERT INTO `u_role` VALUES (1, 'admin', '1');
INSERT INTO `u_role` VALUES (2, 'user', '2');
-- ----------------------------
-- Table structure for u_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `u_role_permission`;
CREATE TABLE `u_role_permission` (
`rid` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
`pid` bigint(20) NULL DEFAULT NULL COMMENT '权限ID',
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_role_permission
-- ----------------------------
INSERT INTO `u_role_permission` VALUES (1, 1, 1);
INSERT INTO `u_role_permission` VALUES (1, 2, 2);
INSERT INTO `u_role_permission` VALUES (1, 3, 3);
INSERT INTO `u_role_permission` VALUES (2, 1, 4);
INSERT INTO `u_role_permission` VALUES (2, 2, 5);
INSERT INTO `u_role_permission` VALUES (2, 3, 6);
-- ----------------------------
-- Table structure for u_user
-- ----------------------------
DROP TABLE IF EXISTS `u_user`;
CREATE TABLE `u_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`nickname` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户昵称',
`email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮箱|登录帐号',
`pswd` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`last_login_time` datetime(0) NULL DEFAULT NULL COMMENT '最后登录时间',
`status` bigint(1) NULL DEFAULT 1 COMMENT '1:有效,0:禁止登录',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_user
-- ----------------------------
INSERT INTO `u_user` VALUES (1, 'admin', 'admin@163.com', 'C4CA4238A0B923820DCC509A6F75849B', '2019-04-27 22:44:44', NULL, 1);
-- ----------------------------
-- Table structure for u_user_role
-- ----------------------------
DROP TABLE IF EXISTS `u_user_role`;
CREATE TABLE `u_user_role` (
`uid` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`rid` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of u_user_role
-- ----------------------------
INSERT INTO `u_user_role` VALUES (1, 2, 1);
SET FOREIGN_KEY_CHECKS = 1;
项目截图:
1、springsecurity 配置类:SecurityConfiguration
只要使用spring security都要有这样一个配置类(如果是类配置的话),继承WebSecurityConfigurerAdapter 主要实现两个方法configure(AuthenticationManagerBuilder auth)和 configure(HttpSecurity http)
AuthenticationManagerBuilder: 主要配置身份认证来源,也就是用户及其角色。
HttpSecurity 主要配置路径:也就是资源的访问权限(是否需要认证,需要什么角色等)。
自定义securityConfiguration:SpringSecurityConfig
package com.zzg.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import com.zzg.security.provider.SpringSecurityProvider;
/**
* spring-security 配置文件
* @author zzg
*
*/
@Configuration
@EnableWebSecurity //开启Spring Security的功能
@EnableGlobalMethodSecurity(prePostEnabled=true)//开启注解控制权限
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* עSpringSecurityProvider
*/
@Autowired
private SpringSecurityProvider provider;
/**
*AuthenticationSuccessHandler
*/
@Autowired
private AuthenticationSuccessHandler securityAuthenticationSuccessHandler;
/**
* AuthenticationFailureHandler
*/
@Autowired
private AuthenticationFailureHandler securityAuthenticationFailHandler;
/**
* 定义需要过滤的静态资源(等价于HttpSecurity的permitAll)
*/
@Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("static/css/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.authorizeRequests()
.antMatchers("/login").permitAll() // 不需要权限路径
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login") // 登入页面
.successHandler(securityAuthenticationSuccessHandler) //自定义成功处理器
.failureHandler(securityAuthenticationFailHandler) //自定义失败处理器
.permitAll()
.and()
.logout();
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
// 自定义身份验证提供者
builder.authenticationProvider(provider);
}
}
2、springsecurity 认证接口:AuthenticationProvider
spring security实现自定义认证,需要实现AuthenticationProvider接口:主要实现方法authenticate(Authentication authentication)
自定义AuthenticationProvider:SpringSecurityProvider
package com.zzg.security.provider;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.zzg.security.userservice.AuthUserDetails;
import com.zzg.security.userservice.CustomUserService;
/**
*自定义身份验证提供者
*
* @author zzg
*
*/
@Component
public class SpringSecurityProvider implements AuthenticationProvider {
@Autowired
private CustomUserService userDetailService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// TODO Auto-generated method stub
String userName = authentication.getName();
String password = (String) authentication.getCredentials();
// 查询用户权限信息
AuthUserDetails userInfo = (AuthUserDetails) userDetailService.loadUserByUsername(userName);
if (userInfo == null) {
throw new UsernameNotFoundException("");
}
// 密码判断
String encodePwd = DigestUtils.md5Hex(password).toUpperCase();
if (!userInfo.getPassword().equals(encodePwd)) {
throw new BadCredentialsException("");
}
return new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(),
userInfo.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return UsernamePasswordAuthenticationToken.class.equals(authentication);
}
}
2、springsecurity 用户详情信息接口:UserDetailsService
spring security实现自定义用户详情信息,需要实现UserDetailsService接口:主要实现方法loadUserByUsername(String username)
自定义UserDetailsService:CustomUserService
package com.zzg.security.userservice;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.zzg.entity.Permission;
import com.zzg.entity.Role;
import com.zzg.entity.RolePermission;
import com.zzg.entity.User;
import com.zzg.entity.UserRole;
import com.zzg.service.PermissionService;
import com.zzg.service.RolePermissionService;
import com.zzg.service.RoleService;
import com.zzg.service.UserRoleService;
import com.zzg.service.UserService;
/**
* 自定义用户查询服务
* @author zzg
*
*/
@Component
public class CustomUserService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private UserRoleService userRoleService;
@Autowired
private RoleService roleService;
@Autowired
private RolePermissionService rolePermissionService;
@Autowired
private PermissionService permissionService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
User user = userService.findByUserName(username);
if(user == null){
throw new UsernameNotFoundException("");
}
List<UserRole> list = userRoleService.findByUid(user.getId());
List<Long> rIds = list.stream().map(UserRole::getRid).collect(Collectors.toList());
List<Role> roles = roleService.findByIds(rIds);
List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList());
List<RolePermission> rolePermissions = rolePermissionService.findByRids(roleIds);
List<Long> pIds = rolePermissions.stream().map(RolePermission::getPid).collect(Collectors.toList());
List<Permission> permissions = permissionService.findByIds(pIds);
AuthUserDetails authUserDetails = new AuthUserDetails(user.getNickname(),user.getPswd(),roles,permissions);
return authUserDetails;
}
}
3、springsecurity 用户信息拓展:UserDetails
spring security 拓展用户信息,继承UserDetails类,主要方法:Collection<? extends GrantedAuthority> getAuthorities() 构建用户权限信息。
自定义UserDetails:AuthUserDetails
package com.zzg.security.userservice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.zzg.entity.Permission;
import com.zzg.entity.Role;
@SuppressWarnings("serial")
public class AuthUserDetails implements UserDetails {
private String nickname;
private String pswd;
private List<Role> roles;
private List<Permission> permission;
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPswd() {
return pswd;
}
public void setPswd(String pswd) {
this.pswd = pswd;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public List<Permission> getPermission() {
return permission;
}
public void setPermission(List<Permission> permission) {
this.permission = permission;
}
public AuthUserDetails(String nickname, String pswd, List<Role> roles, List<Permission> permission) {
super();
this.nickname = nickname;
this.pswd = pswd;
this.roles = roles;
this.permission = permission;
}
public AuthUserDetails(){
this.nickname = "NA";
this.pswd = "NA";
this.roles = Collections.EMPTY_LIST;
this.permission = Collections.EMPTY_LIST;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 基于用户角色名称构建权限信息
List<GrantedAuthority> auths = new ArrayList<>();
List<Role> roles = this.getRoles();
for (Role role : roles) {
auths.add(new SimpleGrantedAuthority(role.getName()));
}
return auths;
}
/**
*
*/
@Override
public String getPassword() {
// TODO Auto-generated method stub
return this.pswd;
}
/**
*
*/
@Override
public String getUsername() {
// TODO Auto-generated method stub
return this.nickname;
}
/**
*
*/
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
/**
*
*/
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
/**
*
*/
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
/**
*
*/
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
4、自定义springsecurity 登入成功处理的Handler:一般需要实现AuthenticationSuccessHandler 接口,覆写onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response, Authentication authentication) throws IOException, ServletException 方法
自定义AuthenticationSuccessHandler:SecurityAuthenticationSuccessHandler
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import com.zzg.redis.util.RedisUtil;
/**
* 用户登入成功
* @author zzg
*
*/
@Component("securityAuthenticationSuccessHandler")
public class SecurityAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private RedisUtil redisUtil;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
// 用户登入成功,补充相关业务逻辑
new DefaultRedirectStrategy().sendRedirect(request, response, "/defaults");
}
}
5、自定义springsecurity 登入失败处理的Handler:一般需要实现AuthenticationFailureHandler接口,覆写onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException 方法
package com.zzg.security.handler;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
/**
* 用户登入失败
* @author zzg
*
*/
@Component("securityAuthenticationFailHandler")
public class SecurityAuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String redirectUrl = "/login?message=" + URLEncoder.encode(exception.getMessage(),"UTF-8");
new DefaultRedirectStrategy().sendRedirect(request, response, redirectUrl);
}
}
6、自定义权限不足处理器,实现AccessDeniedHandler接口,覆写handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) 方法
package com.zzg.security.access.denied;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import com.zzg.security.util.HttpUtils;
/**
* 自定义权限不足处理器
* @author zzg
*
*/
@Component
public class SpringSecurityAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
// TODO Auto-generated method stub
boolean isAjax = HttpUtils.isAjaxRequest(request);
if(isAjax){
// 前端提示授权信息不足
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("权限不足");
} else {
// 后端直接跳转至权限的错误页面
new DefaultRedirectStrategy().sendRedirect(request, response, "/errors");
}
}
}
至此已经完成基于数据库存储的Spring Security权限控制的核心配置。
以下的代码主要是controller、springmvc 配置和工具类代码代码:
Http 工具类:
package com.zzg.security.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
public class HttpUtils {
/**
* 获取请求Body
*
* @param request
* @return
*/
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
/**
* 从request获取登录的IP
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 判断是否为ajax请求
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
if (request.getHeader(HttpHeaders.ACCEPT) != null
&& request.getHeader(HttpHeaders.ACCEPT).indexOf("application/json") > -1
|| (request.getHeader("X-Requested-With") != null
&& request.getHeader("X-Requested-With").equalsIgnoreCase("XMLHttpRequest"))) {
return true;
}
return false;
}
}
springMVC 配置:
package com.zzg.springmvc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 访问路径配置类 可以理解成做简单访问过滤的,转发到相应的视图页面
*
* @author Veiking
*/
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// TODO Auto-generated method stub
registry.addViewController("/login").setViewName("login.html");
registry.addViewController("/").setViewName("index.html");
registry.addViewController("/index").setViewName("index.html");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// TODO Auto-generated method stub
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/**");
}
}
package com.zzg.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
/**
* 鉴权用户是否拥有指定权限
* @param model
* @param tt
* @return
*/
@RequestMapping("/admin")
@PreAuthorize("hasAuthority('admin')")
public String admin(Model model, String tt) {
return "admin";
}
@RequestMapping("/hello")
public String hello(Model model, String tt) {
return "hello";
}
/**
* 登入成功跳转页面
* @param model
* @param tt
* @return
*/
@RequestMapping("/defaults")
public String defaults(Model model, String tt) {
return "defaults";
}
/**
* 权限不足跳转页面
* @param model
* @param tt
* @return
*/
@RequestMapping("/errors")
public String errors(Model model, String tt) {
return "errors";
}
}
静态页面:
admin.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>ADMIN</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 40px; }
</style>
</head>
<body>
<h1>ADMIN</h1>
<br/>你好:<a sec:authentication="name"></a>
<p>
<a th:href="@{/index}"> INDEX</a>
<a th:href="@{/admin}"> | ADMIN</a>
<a th:href="@{/hello}"> | HELLO</a>
<br/><hr/>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</p>
</body>
</html>
defaults.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>成功默认登入页面</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 40px; }
</style>
</head>
<body>
<h1>成功默认登入页面</h1>
<br/>成功默认登入页面:<a sec:authentication="name"></a>
<p>
<a th:href="@{/index}"> INDEX</a>
<a th:href="@{/admin}"> | ADMIN</a>
<a th:href="@{/hello}"> | HELLO</a>
<br/><hr/>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</p>
</body>
</html>
error.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>方法权限不足提示页面</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 40px; }
</style>
</head>
<body>
<h1>方法权限不足提示页面</h1>
<br/>方法权限不足提示页面:<a sec:authentication="name"></a>
<p>
<a th:href="@{/index}"> INDEX</a>
<a th:href="@{/admin}"> | ADMIN</a>
<a th:href="@{/hello}"> | HELLO</a>
<br/><hr/>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</p>
</body>
</html>
hello.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>
<meta content="text/html;charset=UTF-8"/>
<title>HELLO</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 40px; }
</style>
</head>
<body>
<h1>HELLO</h1>
<br/>你好:<a sec:authentication="name"></a>
<p>
<a sec:authorize="hasAuthority('admin')" th:href="@{/index}"> INDEX</a>
<a sec:authorize="hasAuthority('admin')" th:href="@{/admin}"> | ADMIN</a>
<a sec:authorize="hasAuthority('admin')" th:href="@{/hello}"> | HELLO</a>
<br/><hr/>
<form th:action="@{/logout}" method="post" sec:authorize="hasAuthority('admin')">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</p>
</body>
</html>
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>主页</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 40px; }
</style>
</head>
<body>
<h1>INDEX</h1>
<br/>你好:<a sec:authentication="name"></a>
<p>
<a sec:authorize="hasAuthority('user')" th:href="@{/index}"> INDEX</a>
<a sec:authorize="hasAuthority('admin')" th:href="@{/admin}"> | ADMIN</a>
<a sec:authorize="hasAuthority('user')" th:href="@{/hello}"> | HELLO</a>
<br/><hr/>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</p>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<title>登录</title>
<link rel="stylesheet" th:href="@{static/css/bootstrap.min.css}"/>
<style type="text/css">
body { padding: 20px; }
.starter-template { width:350px; padding: 0 40px; text-align: center; }
</style>
</head>
<body>
<p>
<a th:href="@{/index}"> INDEX</a>
<a th:href="@{/admin}"> | ADMIN</a>
<a th:href="@{/hello}"> | HELLO</a>
<br/>
</p>
<hr/>
<div class="starter-template">
<p th:if="${param.logout}" class="bg-warning">已成功注销</p><!-- 1 -->
<p th:if="${param.error}" class="bg-danger">有错误,请重试</p> <!-- 2 -->
<h2>使用用户名密码登录</h2>
<form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 -->
<div class="form-group">
<label for="username">账号</label>
<input type="text" class="form-control" name="username" value="" placeholder="账号" />
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" name="password" placeholder="密码" />
</div>
<div class="form-group">
<input type="submit" id="login" value="登录" class="btn btn-primary" />
</div>
</form>
</div>
</body>
</html>
源码下载地址:待补充
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。