本例所覆盖的内容:
1. 使用Spring Security管理用户身份认证、登录退出
2. 用户密码加密及验证
3. 采用数据库的方式实现Spring Security的remember-me功能
4. 获取登录用户信息。
5.使用Spring Security管理url和权限
本例所使用的框架:
1. Spring boot
2. Spring MVC
3. Spring Security
4. Spring Data JPA
5. thymeleaf
6.gradle
一、 整合Spring Security
在build.gradle中加入如下片段:
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-security")
testCompile("org.springframework.boot:spring-boot-starter-test")
testCompile("org.springframework.security:spring-security-test")
使用Spring Security4的四种方法概述
那么在Spring Security4的使用中,有4种方法:
- 一种是全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中;
- 二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置。
- 三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
- 四是修改spring security的源代码,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。 前者是将配置文件 或数据库中存储的资源(url)提取出来加工成为url和权限列表的Map供Security使用,后者提取用户名和权限组成一个完整的(UserDetails)User 对象,该对象可以提供用户的详细信息供AuthentationManager进行认证与授权使用。
我们今天来实现一下第三种。
当然,spring security4毕竟是西方国家的东西,以英文为主,使用习惯和文化的差异共存,况且为了适应大多数Web应用的权限管理,作者将Spring Security4打造的精简而灵活。精简指Spring Security4对用户和权限的表设计的非常简单,并且没有采用数据库来管理资源(URL)。这样的话,对于我们国人用户来说,是个很大的遗憾,这个遗憾甚至能够影响到我们对安全框架的选型。你想啊,在国内大多数项目中,均设置了比较复杂的权限控制,一般就会涉及到用户、角色、资源3张表,若要加上3张表之间的对应关系表2张,得有5张表。
但是,Spring Security4提供了灵活的扩展方法。具体应该扩展哪些类呢? 或者到底Spring Security3工作的流程如何,你不妨参看下面一篇文章,就会获得
一些启示,网址为:http://www.blogjava.net/SpartaYew/archive/2011/06/15/350630.html, 哈哈,谢谢分享。
还有一个地址很有价值,http://download.csdn.net/detail/muddled/8981809,我就参考着上面的介绍扩展了4个类。
首先来说一下第三种方法的实现流程,我画了一张简易版流程图,帮助大家理解spring security4 的工作机制:
下面我们就来根据这个图中标注出的,重要的几个4个类来配置吧!
- 当然要现在application.properties配置文件中配置好数据库。
- 开始配置相关的实体类 SysUser.java SRole.java SysResource.java SysResourceRole.java
package security.entity; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @Entity @Table(name = "s_user")//code11 public class SysUser implements java.io.Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false) private Integer id; @Column(name = "name", length = 120) private String name; //用户名 @Column(name = "email", length = 50) private String email;//用户邮箱 @Column(name = "password", length = 120) private String password;//用户密码 @Temporal(TemporalType.DATE) @Column(name = "dob", length = 10) private Date dob;//时间 @OneToMany(fetch = FetchType.EAGER, mappedBy = "SUser") private Set<SysRole> SysRoles = new HashSet<SysRole>(0);// 所对应的角色集合 public SysUser() { } public SysUser(String name, String email, String password, Date dob, Set<SysRole> SysRoles) { this.name = name; this.email = email; this.password = password; this.dob = dob; this.SysRoles = SysRoles; } public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getEmail() { return this.email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } public Date getDob() { return this.dob; } public void setDob(Date dob) { this.dob = dob; } @OneToMany(fetch = FetchType.EAGER, mappedBy = "SUser") public Set<SysRole> getSysRoles() { return this.SysRoles; } public void setSRoles(Set<SysRole> SysRoles) { this.SysRoles = SysRoles; } }
package security.entity; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; //角色表 @Entity @Table(name="s_role") public class SysRole { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column (name="id",length=10) private int id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "uid", nullable = false) private SysUser SUser;//角色对应的用户实体 @Column(name="name",length=100) private String name;//角色名称 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 SysUser getSUser() { return SUser; } public void setSUser(SysUser sUser) { SUser = sUser; } }
package cn.paybay.ticketManager.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="s_resource") public class SysResource { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column (name="id",length=10) private int id; @Column(name="resourceString",length=1000) private String resourceString;//url @Column(name="resourceId",length=50) private String resourceId;//资源ID @Column(name="remark",length=200) private String remark;//备注 @Column(name="resourceName",length=400) private String resourceName;//资源名称 @Column(name="methodName",length=400) private String methodName;//资源所对应的方法名 @Column(name="methodPath",length=1000) private String meth