SSM——用户、角色、权限操作

1. 数据库与表结构

1.1 用户表
1.1.1 用户表信息描述 users

SSM——用户、角色、权限操作_第1张图片

1.1.2 sql语句
CREATE TABLE users(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
email VARCHAR2(50) UNIQUE NOT NULL,
username VARCHAR2(50),
PASSWORD VARCHAR2(50),
phoneNum VARCHAR2(20),
STATUS INT
)
 1.1.3 实体类
public class UserInfo {
private String id;
private String username;
private String email;
private String password;
private String phoneNum;
private int status;
private String statusStr;
private List roles;
}
1.2 角色表
1.2.1 角色表信息描述 role

SSM——用户、角色、权限操作_第2张图片

1.2.2 sql语句 
CREATE TABLE role(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
roleName VARCHAR2(50) ,
roleDesc VARCHAR2(50)
)
 1.2.3 实体类
public class Role {
private String id;
private String roleName;
private String roleDesc;
private List permissions;
private List users;
}
1.2.4 用户与角色关联关系

用户与角色之间是多对多关系,我们通过 user_role 表来描述其关联,在实体类中 User 中存在 List ,在 Role 中有 List.

而角色与权限之间也存在关系,我们会在后面介绍

CREATE TABLE users_role(
userId varchar2(32),
roleId varchar2(32),
PRIMARY KEY(userId,roleId),
FOREIGN KEY (userId) REFERENCES users(id),
FOREIGN KEY (roleId) REFERENCES role(id)
)
1.3 资源权限表
1.3.1 权限资源表描述 permission

SSM——用户、角色、权限操作_第3张图片

1.3.2 sql语句 
CREATE TABLE permission(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
permissionName VARCHAR2(50) ,
url VARCHAR2(50)
)

 1.3.3 实体类

public class Permission {
private String id;
private String permissionName;
private String url;
private List roles;
}
1.3.4. 权限资源与角色关联关系

权限资源与角色是多对多关系,我们使用 role_permission 表来描述。在实体类 Permission 中存在 List, 在 Role 类中有List

CREATE TABLE role_permission(
permissionId varchar2(32),
roleId varchar2(32),
PRIMARY KEY(permissionId,roleId),
FOREIGN KEY (permissionId) REFERENCES permission(id),
FOREIGN KEY (roleId) REFERENCES role(id)
)

2.Spring Security 概述

2.1 Spring Security 介绍

Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。
( https://projects.spring.io/spring-security/ ) Spring Security 为基于 J2EE 企业应用软件提供了全面安全服务。特别是使用领先的J2EE 解决方案 -Spring 框架开发的企业软件项目。人们使用 Spring Security 有很多种原因,不过通常吸引他们的是在J2EE Servlet 规范或 EJB 规范中找不到典型企业应用场景的解决方案。 特别要指出的是他们不能再WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用系统进行重新配 置安全。使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安全特性。 安全包括两个主要操作。
“ 认证 ” ,是为用户建立一个他所声明的主体。主题一般式指用户,设备或可以在你系 统中执行动作的其他系统。
“ 授权 ” 指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由 身份验证过程建立了。
这些概念是通用的,不是 Spring Security 特有的。在身份验证层面, Spring Security 广泛支持各种身份验证模式,这些验证模型绝大多数都由第三方提供,或则正在开发的有关标准机构提供的,例如 Internet Engineering Task Force.作为补充, Spring Security 也提供了自己的一套验证功能。
Spring Security 目前支持认证一体化如下认证技术: HTTP BASIC authentication headers ( 一个基于 IEFT RFC 的标准) HTTP Digest authentication headers ( 一个基于 IEFT RFC 的标准 ) HTTP X.509 client certifificate exchange(一个基于 IEFT RFC 的标准 ) LDAP ( 一个非常常见的跨平台认证需要做法,特别是在大环境 ) Form-based authentication (提供简单用户接口的需求 ) OpenID authentication Computer Associates Siteminder JA-SIG Central Authentication Service (CAS,这是一个流行的开源单点登录系统 ) Transparent authentication context propagation for Remote Method Invocation and HttpInvoker (一个 Spring 远程调用协议 )
Maven 依赖



org.springframework.security
spring-security-web
5.0.1.RELEASE


org.springframework.security
spring-security-config
5.0.1.RELEASE

2.2 Spring Security 快速入门
2.2.1 pom.xml

4.0.0
spring_security_demo
SpringSecurity_quickStart
0.0.1-SNAPSHOT
war

5.0.2.RELEASE
5.0.1.RELEASE



org.springframework
spring-core
${spring.version}


org.springframework
spring-web
${spring.version}


org.springframework
spring-webmvc
${spring.version}


org.springframework
spring-context-support
${spring.version}


org.springframework
spring-test
${spring.version}


org.springframework
spring-jdbc
${spring.version}


org.springframework.security
spring-security-web
${spring.security.version}


org.springframework.security
spring-security-config
${spring.security.version}


javax.servlet
javax.servlet-api
3.1.0
provided






org.apache.maven.plugins
maven-compiler-plugin
3.2

1.8
1.8
UTF-8



org.apache.tomcat.maven
tomcat7-maven-plugin


8080

/




2.2.2 web.xml

contextConfigLocation
classpath:spring-security.xml


org.springframework.web.context.ContextLoaderListener


springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy


springSecurityFilterChain
/*
2.2.3 spring security 配置















2.2.4 测试

我们在 webapp 下创建一个 index.html 页面,在页面中任意写些内容。

SSM——用户、角色、权限操作_第4张图片

当我们访问 index.html 页面时发现会弹出登录窗口,可能你会奇怪,我们没有建立下面的登录页面,为什么 Spring Security会跳到上面的登录页面呢?这是我们设置 http 的 auto-confifig=”true” 时 Spring Security 自动为我们生成的。

2.2.5 使用自定义页面

2.2.5.1 spring-security.xml 配置
























2.2.5.2 login.html





Insert title here


用户名:
密码:

2.2.5.3 success.html





Insert title here


success html
退出

2.2.5.4 failer.html





Insert title here

登录失败

2.3 Spring Security 使用数据库认证

在 Spring Security 中如果想要使用数据进行认证操作,有很多种操作方式,这里我们介绍使用 UserDetails 、 UserDetailsService来完成操作。
UserDetails

public interface UserDetails extends Serializable {
Collection getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}

UserDetails 是一个接口,我们可以认为 UserDetails 作用是于封装当前进行认证的用户信息,但由于其是一个接口,所以我们可以对其进行实现,也可以使用Spring Security 提供的一个 UserDetails 的实现类 User 来完成操作
以下是 User 类的部分代码

public class User implements UserDetails, CredentialsContainer {
private String password;
private final String username;
private final Set authorities;
private final boolean accountNonExpired; //帐户是否过期
private final boolean accountNonLocked; //帐户是否锁定
private final boolean credentialsNonExpired; //认证是否过期
private final boolean enabled; //帐户是否可用
}

UserDetailsService

public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

上面将 UserDetails 与 UserDetailsService 做了一个简单的介绍,那么我们具体如何完成 Spring Security 的数据库认证操作哪,我们通过用户管理中用户登录来完成Spring Security 的认证操作。

3. 用户管理

3.1 用户登录

spring security 的配置





3.1.1. 登录页面 login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>





 
数据 - AdminLTE2定制版 | Log in
 

 






 

	
	
 
	
	
	
	
	
	
	

 
3.1.2.Service
public interface IUserService extends UserDetailsService{
}
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = userDao.findByUsername(username);
List roles = userInfo.getRoles();
List authoritys = getAuthority(roles);
User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(),
userInfo.getStatus() == 0 ? false : true, true, true, true, authoritys);
return user;
}
private List getAuthority(List roles) {
List authoritys = new ArrayList();
for (Role role : roles) {
authoritys.add(new SimpleGrantedAuthority(role.getRoleName()));
}
return authoritys;
}
}
3.1.3.IUserDao
public interface IUserDao {
@Select("select * from user where id=#{id}")
public UserInfo findById(Long id) throws Exception;
@Select("select * from user where username=#{username}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(column = "username", property = "username"),
@Result(column = "email", property = "email"),
@Result(column = "password", property = "password"),
@Result(column = "phoneNum", property = "phoneNum"),
@Result(column = "status", property = "status"),
@Result(column = "id", property = "roles", javaType = List.class, many =
@Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")) })
public UserInfo findByUsername(String username);
}
3.2 用户退出

使用 spring security 完成用户退出,非常简单

配置

页面中

注销
3.3 用户查询
3.3.1. 用户查询页面 user-list.jsp

请在资料中查看具体代码

3.3.2.UserControlle
@Controller
@RequestMapping("/user")
public class UserControlller {
@RequestMapping("/findAll.do")
public ModelAndView findAll() throws Exception {
List users = userService.findAll();
ModelAndView mv = new ModelAndView();
mv.addObject("userlist", users);
mv.setViewName("user-list");
return mv;
}
}
3.3.3.Dao
@Select("select * from user")
public List findAll();
3.4 用户添加
3.4.1. 用户添加页面 user-add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>






数据 - AdminLTE2定制版


 


 
 























 

 
	

用户管理 用户表单

用户信息
用户名称
密码
邮箱
联系电话
用户状态
3.4.2.UserController
@Controller
@RequestMapping("/user")
public class UserControlller {
@Autowired
private IUserService userService;
@RequestMapping("/save.do")
public String save(UserInfo user) throws Exception {
userService.save(user);
return "redirect:findAll.do";
}
}
3.4.3.Service
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void save(UserInfo user) throws Exception {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userDao.save(user);
}
}

前期我们的用户密码没有加密,现在添加用户时,我们需要对用户密码进行加密


3.4. 4.Dao
@Insert("insert into user(email,username,password,phoneNum,status) value(#{email},#
{username},#{password},#{phoneNum},#{status})")
public void save(UserInfo user) throws Exception;
3.5 用户详情
3.5.1. 用户详情页面 user-show.jsp

请在资料中查看页面详细代码

注意:需要添加 js

$("#collapse-table").treetable({ expandable : true });
3.5.2.UserController
@Controller
@RequestMapping("/user")
public class UserControlller {
@Autowired
private IUserService userService;
@RequestMapping("/findById.do")
public ModelAndView findById(@RequestParam(name = "id", required = true) Long id) throws
Exception {
UserInfo user = userService.findById(id);
ModelAndView mv = new ModelAndView();
mv.addObject("user", user);
mv.setViewName("user-show");
return mv;
}
}
3.5.3.Dao
@Select("select * from user where id=#{id}")
@Results({ @Result(id = true, property = "id", column = "id"), @Result(column = "username",
property = "username"),
@Result(column = "email", property = "email"), @Result(column =
"password", property = "password"),
@Result(column = "phoneNum", property = "phoneNum"), @Result(column =
"status", property = "status"),
@Result(column = "id", property = "roles", javaType = List.class, many =
@Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")) })
public UserInfo findById(Long id) throws Exception;
@Select("select * from role where id in( select roleId from user_role where userId=#{userId})")
@Results(
{
@Result(id=true,column="id",property="id"),
@Result(column="roleName",property="roleName"),
@Result(column="roleDesc",property="roleDesc"),
@Result(column="id",property="permissions",javaType=List.class,many=@Many(select="com.itheima.ssm
.dao.IPermissionDao.findByRoleId"))
})
public List findRoleByUserId(Long userId);

我们需要将用户的所有角色及权限查询出来所以需要调用 IRoleDao 中的 fifindRoleByUserId, 而在 IRoleDao 中需要调用IPermissionDao 的 fifindByRoleId

@Select("select * from permission where id in (select permissionId from role_permission where
roleId=#{roleId})")
public List findByRoleId(Long roleId);

4. 角色管理

4.1 角色查询
4.1.1. 角色页面 role-list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>






 
数据 - AdminLTE2定制版


 


 






















 

 
	

角色管理 全部角色

列表

ID 角色名称 描述 操作
${role.id } ${role.roleName } ${role.roleDesc } 详情 删除角色 添加权限
4.1.2.RoleControlller
@RequestMapping("/role")
@Controller
public class RoleController {
@Autowired
private IRoleService roleService;
@RequestMapping("/findAll.do")
public ModelAndView findAll() throws Exception {
List roleList = roleService.findAll();
ModelAndView mv = new ModelAndView();
mv.addObject("roleList", roleList);
mv.setViewName("role-list");
return mv;
}
4.1.3.Dao
@Select("select * from role")
public List findAll();
4.2 角色添加
4.2.1. 角色添加页面 role-add.jsp

请在页面中查看详细代码

4.2.2.RoleControlller
@RequestMapping("/role")
@Controller
public class RoleController {
@Autowired
private IRoleService roleService;
@RequestMapping("/save.do")
public String save(Role role) {
roleService.save(role);
return "redirect:findAll.do";
}
}
4.2.3.Dao
@Insert("insert into role(roleName,roleDesc) value(#{roleName},#{roleDesc})")
public void save(Role role);

5. 资源权限管理

5.1 资源权限查询
5.1.1. 权限资源页面 permission-list.jsp

请在资料中查看详细代码

5.1.2.PermissionControlle
@RequestMapping("/permission")
@Controller
public class PermissionController {
@Autowired
private IPermissionService permissionService;
@RequestMapping("/findAll.do")
public ModelAndView findAll() throws Exception {
List permissionList = permissionService.findAll();
ModelAndView mv = new ModelAndView();
mv.addObject("permissionList", permissionList);
mv.setViewName("permission-list");
return mv;
}
}
5.1.3.Dao
@Select("select * from permission")
public List findAll();
5.2 资源权限添加
5.2.1. 权限资源添加页面 permission-add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>






数据 - AdminLTE2定制版


 


 
 























 
	
 
	

资源权限管理 资源权限表单

资源权限信息
权限名称
RUL
5.2.2.PermissionController
@RequestMapping("/permission")
@Controller
public class PermissionController {
@Autowired
private IPermissionService permissionService;
@RequestMapping("/save.do")
public String save(Permission p) throws Exception {
permissionService.save(p);
return "redirect:findAll.do";
}
}
5.2.3.Dao
@Insert("insert into permission(permissionName,url) value(#{permissionName},#{url})")
public void save(Permission p);

6. 权限关联与控制

6.1 用户角色关联

用户与角色之间是多对多关系,我们要建立它们之间的关系,只需要在中间表 user_role 插入数据即可。

6.1.1. 用户角色关联相关页面

在 user-list.jsp 页面上添加链接

添加角色

展示可以添加角色的页面 user-role-add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>






数据 - AdminLTE2定制版


 


 
 























 

 
	

用户管理 添加角色表单

ID 角色名称 角色描述
${role.id} ${role.roleName } ${role.roleDesc}
6.1.2.UserController

findUserByIdAndAllRole(Long id) 方法
此方法用于查找要操作的用户及可以添加的角色,参数是要操作的用户 id
 

@RequestMapping("/findUserByIdAndAllRole.do")
public ModelAndView findUserByIdAndAllRole(Long id) throws Exception {
UserInfo user = userService.findById(id);
List roleList = roleService.findOtherRole(id);
ModelAndView mv = new ModelAndView();
mv.addObject("user", user);
mv.addObject("roleList", roleList);
mv.setViewName("user-role-add");
return mv;
}

调用 IUserService 的 fifindById 方法获取要操作的 User
调用 IRoleService 的 fifindOtherRole 方法用于获取可以添加的角色信息
addRoleToUser(Long userId,Long[] ids) 方法些方法用于在用户与角色之间建立关系,参数userId 代表要操作的用户 id, 参数 ids 代表的是角色 id 数组

@RequestMapping("/addRoleToUser.do")
public String addRoleToUser(Long userId, Long[] ids) throws Exception {
userService.addRoleToUser(userId,ids);
return "redirect:findAll.do";
}
6.1.3.Dao

IRoleDao

@Select("select * from role where id not in( select roleId from user_role where userId=#
{id})")
public List findOtherRole(Long id);

用于查找可以添加的角色

IUserDao

@Insert("insert into user_role(userId,roleId) value(#{userId},#{roleId})")
public void addRoleToUser(@Param("userId") Long userId, @Param("roleId") Long roleId);

用于添加用户与角色关系

6.2 角色权限关联

角色与权限之间是多对多关系,我们要建立它们之间的关系,只需要在中间表 role_permission 插入数据即可。

6.2.1. 角色权限关联相关页面

在 role-list.jsp 页面上添加链接

添加权限

展示可以添加权限的页面 role-permission-add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>






数据 - AdminLTE2定制版


 


 
 























 

 
	

角色管理 添加权限表单

ID 权限名称 权限URL
${permission.id} ${permission.permissionName } ${permission.url}
6.2.2.RoleController

findRoleByIdAndAllPermission(Long roleId) 方法
此方法用于查找要操作的角色及可以添加的权限,参数是要操作的角色 id

@RequestMapping("/findRoleByIdAndAllPermission.do")
public ModelAndView findRoleByIdAndAllPermission(@RequestParam(name = "id", required
= true) Long roleid)
throws Exception {
ModelAndView mv = new ModelAndView();
Role role = roleService.findById(roleid);
mv.addObject("role", role);
List permissionList =
permissionService.findOtherPermission(roleid);
mv.addObject("permissionList", permissionList);
mv.setViewName("role-permission-add");
return mv;
}

调用 IRoleService 的 fifindById 方法获取要操作的 Role
调用 IPermissionService 的 fifindOtherPermission 方法用于获取可以添加的权限信息
addPermissionToRole(Long roleId,Long[] ids) 方法
些方法用于在角色与权限之间建立关系,参数 roleId 代表要操作的角色 id, 参数 permissionIds 代表的是权限 id数组

@RequestMapping("/addPermissionToRole.do")
public String addPermissionToRole(@RequestParam(name = "roleId") Long roleId,
@RequestParam(name = "ids") Long[] permissionIds) throws Exception {
roleService.addPermissionToRole(roleId, permissionIds);
return "redirect:findAll.do";
}
6.2.3.Dao

 IPermissionDao

@Select("select * from permission where id not in (select permissionId from role_permission
where roleId=#{roleId})")
public List findOtherPermission(Long roleid);

用于查找可以添加的权限

IRoleDao

@Insert("insert into role_permission (roleId,permissionId) value (#{roleId},#
{permissionId})")
public void addPermissionToRole(@Param("roleId") Long roleId, @Param("permissionId") Long
permissionId);

用于绑定角色与权限的关系

6.3 服务器端方法级权限控制

在服务器端我们可以通过 Spring security 提供的注解对方法来进行权限控制。 Spring Security 在方法的权限控制上支持三种类型的注解,JSR-250 注解、 @Secured 注解和支持表达式的注解,这三种注解默认都是没有启用的,需要单独通过global-method-security 元素的对应属性进行启用

6.3.1. 开启注解使用

配置文件



注解开启
@EnableGlobalMethodSecurity : Spring Security 默认是禁用注解的,要想开启注解,需要在继承
WebSecurityConfifigurerAdapter 的类上加 @EnableGlobalMethodSecurity 注解,并在该类中将
AuthenticationManager 定义为 Bean 。

6.3.2.JSR-250 注解

@RolesAllowed 表示访问对应方法时所应该具有的角色

示例:
@RolesAllowed({"USER", "ADMIN"}) 该方法只要具有 "USER", "ADMIN" 任意一种权限就可以访问。这里可以省略前缀ROLE_ ,实际的权限可能是 ROLE_ADMIN

@PermitAll 表示允许所有的角色进行访问,也就是说不进行权限控制

@DenyAll 是和 PermitAll 相反的,表示无论什么角色都不能访问

6.3.3. 支持表达式的注解

@PreAuthorize 在方法调用之前 , 基于表达式的计算结果来限制对方法的访问

示例:
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
void changePassword(@P("userId") long userId ){ }
这里表示在 changePassword 方法执行之前,判断方法参数 userId 的值是否等于 principal 中保存的当前用户的
userId ,或者当前用户是否具有 ROLE_ADMIN 权限,两种符合其一,就可以访问该方法。

 @PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常

示例:
@PostAuthorize
User getUser("returnObject.userId == authentication.principal.userId or
hasPermission(returnObject, 'ADMIN')");

@PostFilter 允许方法调用 , 但必须按照表达式来过滤方法的结果

@PreFilter 允许方法调用 , 但必须在进入方法之前过滤输入值

6.3.4.@Secured 注解

@Secured 注解标注的方法进行权限控制的支持,其值默认为 disabled 

示例:
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("ROLE_TELLER")

6.4 页面端标签控制权限

在 jsp 页面中我们可以使用 spring security 提供的权限标签来进行权限控制

6.4.1. 导入

maven 导入


org.springframework.security
spring-security-taglibs
version

页面导入

<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
6.4.2. 常用标签

在 jsp 中我们可以使用以下三种标签,其中 authentication 代表的是当前认证对象,可以获取当前认证对象信息,例如用户名。其它两个标签我们可以用于权限控制

6.4.2.1 authentication

hasPermission : hasPermission 属性用于指定以逗号分隔的权限列表
domainObject : domainObject 用于指定对应的域对象
var : var 则是用以将鉴定的结果以指定的属性名存入 pageContext 中,以供同一页面的其它地方使用

你可能感兴趣的:(java,oracle,spring,servlet,数据库)