SpringSecurity结合数据表实现权限认证:
下面的案例是在SpringBoot框架实现的:
步骤一:准备数据库表 以下是五张表的脚本
### 用户表
create table Sys_User
(
id int primary key auto_increment,
username varchar(32),
password varchar(32)
); ###角色表
create table Sys_Role
(
id int primary key auto_increment,
name varchar(32)
); ###权限表
create table Sys_Permission
(
id int primary key auto_increment,
name varchar(32),
description varchar(256),
url varchar(256),
pid int
); ###用户角色表
create table Sys_user_role
(
id int primary key auto_increment,
sys_user_id int,
sys_role_id int
); ###角色权限表
create table Sys_role_permission
(
id int primary key auto_increment,
role_id int,
permission_id int
); insert into SYS_USER(id,username,password) values(1,'admin','admin');
insert into SYS_USER(id,username,password) values(2,'abel','abel'); insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
insert into SYS_ROLE(id,name) values(2,'ROLE_USER'); insert into SYS_USER_ROLE(SYS_USER_ID,SYS_ROLE_ID) values(1,1);
insert into SYS_USER_ROLE(SYS_USER_ID,SYS_ROLE_ID) values(2,2); BEGIN;
INSERT INTO `Sys_permission` VALUES('1','ROLE_HOME','home','/',null),('2','ROLE_ADMIN','ABel','admin',null);
COMMIT; BEGIN;
INSERT INTO `Sys_role_permission` VALUES('1','1','1'),('2','1','2'),('3','2','1');
COMMIT; 步骤二:
//1.1 application的配置
spring.datasource.url=jdbc:mysql://localhost:3306/y2156
spring.datasource.username=root
spring.datasource.password=55163
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.max-active = 20
spring.datasource.max-idle = 8
spring.datasource.min-idle=8
spring.datasource.initial-sixe=10 ######Spring jpa的配置信息
spring.jpa.database=MYSQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect server.port=8080 cn.happy.name = weilengdeyu ###es的相关配置
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.properties.transport.tcp.connect_timeout=5s ##模板引擎的配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.cache = false
spring.thymeleaf.mode=HTML5 ###让配置文件找到mapping下的小配置文件
mybatis.mapper-locations=classpath:mapping/*.xml
###别名设置
mybatis.type-aliases-package=cn.happy.entity //1.2 在pom.xml中引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <!--thymeleaf和springsecurity整合的依赖-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency> <!--thymeleaf 新的模板引擎,比jsp要出色-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
 步骤三:准备ui层
// 1.1. login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
<script type="text/javascript" th:src="@{/js/jquery-3.3.1.js}"></script>
<script type="text/javascript"> </script>
</head>
<body>
<div>
<form th:action="@{/login}" method="post">
<h2>请登录</h2>
用户名:<input name="username" type="text"/><br/>
密码:<input name="password" type="password"/><br/>
<input type="submit" value="登录"/><br/>
<div th:if="${loginError}"></div>
<div th:text="${errorMsg}"></div>
</form>
</div>
</body>
</html> //1.2 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>
<meta charset="UTF-8">
<title>博客系统</title>
<script type="text/javascript" th:src="@{/js/jquery-3.3.1.js}"></script>
<script type="text/javascript"> </script>
</head>
<body>
<div>
<!--authorize:认证,授权-->
<div sec:authorize="isAuthenticated()">
<p>登录的用户名为:<span sec:authentication="name"></span></p>
<p>登录的权限为:<span sec:authentication="principal.authorities"></span></p>
</div>
</div>
</body>
</html> 步骤四: 在entity层创建实体类
// 1.1 SysUser类
public class SysUser {
private Integer id;
private String username;
private String password; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
} //1.2. Permission 类
public class Permission {
private int id;
//权限名称
private String name;
//权限描述
private String description;
//授权链接
private String url;
//父节点id
private int pid; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public int getPid() {
return pid;
} public void setPid(int pid) {
this.pid = pid;
}
} 步骤五:
在dao层创建需要的接口
//1.1 创建IUserDAO
import cn.happy.entity.SysUser;
public interface IUserDAO {
//01.根据用户名称检索用户对象 Spring Security
public SysUser loadUserByUsername(String username);
} //1.2 创建IPermissionDAO
import cn.happy.entity.Permission;
import java.util.List;
public interface IPermissionDAO {
//01.查询所有权限集合 看用户能不能访问某个资源
public List<Permission> findAll();
//02.根据用户编号查询权限集合
public List<Permission> findByAdminUserId(int userId);
} 步骤六:
注意: service层不用写接口,因为SpringSecurity框架已经帮我们封装好了相关的方法
所以我们可以直接研发实现类即可:
import cn.happy.dao.IPermissionDAO;
import cn.happy.dao.IUserDAO;
import cn.happy.entity.Permission;
import cn.happy.entity.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
//用户详情服务
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import java.util.ArrayList;
import java.util.List; public class UserServiceImpl implements UserDetailsService {
//在service层需要植入DAO的接口
@Autowired
private IUserDAO userDAO;
@Autowired
private IPermissionDAO permissionDAO;
@Override
public UserDetails loadUserByUsername(String username){
//1.调度的是我自己在DAO层定制的方法,只不过有一个巧合,就是我自己定制的方法和spring security中的方法名称一致。
SysUser sysUser = userDAO.loadUserByUsername(username);
//断定
if(sysUser!=null){ //有用户对象
//根据用户对象中的用户编号,获取该用户所拥有的所有权限集合
List<Permission> permissions=permissionDAO.findByAdminUserId(sysUser.getId());
//如果想让你的权限在UI层可以使用,必须进行包装,保证类型是GrantedAuthority
//1.先准备一个和框架对接的容器
List<GrantedAuthority> grantedAuthorities=new ArrayList<>();
//2.进行容器的替换
for(Permission permission:permissions){
//每个permission对象都是一个权限对象
if(permission != null && permission.getName()!= null){ //进行了双重校验,保证权限的准确性
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
//将单个grantedAuthority对象添加到集合中
grantedAuthorities.add(grantedAuthority);
}
}
return new User(sysUser.getUsername(),sysUser.getPassword(),grantedAuthorities);
}else{
throw new UsernameNotFoundException("admin:"+username+"do not exits");
} }
} 步骤七:
// 1.1.创建WebSecurityConfig 继承了 WebSecurityConfigurerAdapter
import cn.happy.service.impl.UserServiceImpl;
import cn.happy.util.MyPasswordEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated() //任何请求,登录后可以访问
.and().formLogin() //基于表单的登录
.loginPage("/login") //登录页面
.failureUrl("/login-error") //错误页面
.permitAll() //登录和错误页面用户可以任意访问
.and()
.logout().permitAll();//注销行为可以任意访问
} @Bean
//UserDetailsService是一个接口
//意思是@Bean明确的指示了一种方法,什么方法呢----产生一个bean的方法,并且将bean实例交给spring容器管理
UserDetailsService customUserService(){
//向spring容器直接植入了一个Service
return new UserServiceImpl();
}
//定制了一个configuration
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {//认证管理构建器
auth.userDetailsService(customUserService()).passwordEncoder(new MyPasswordEncoder()); //user Details Service验证
}
} //1.2.上面的程序中需要传入一个MyPasswordEncoder()参数
那么我们就来创建一个自定义的密码编辑器 import org.springframework.security.crypto.password.PasswordEncoder; public class MyPasswordEncoder implements PasswordEncoder { @Override
public String encode(CharSequence arg0) {
return arg0.toString();
} @Override
public boolean matches(CharSequence arg0, String arg1) {
return arg1.equals(arg0.toString());
}
} 步骤八:
创建controller,实现一系列的调度和访问
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; @Controller
public class MainController {
@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";
}
}
05-11 17:04