SSM权限操作
1. 数据库与表结构
1.1 用户表
1.1.1 用户表信息描述users
序号 | 字段名称 | 字段类型 | 字段描述 |
---|---|---|---|
1 | id | varchar2 | 无意义,主键uuid |
2 | varchar2 | 非空,唯一 | |
3 | username | varchar2 | 用户名 |
4 | password | varchar2 | 密码(加密) |
5 | phoneNum | varchar2 | 电话 |
6 | status | int | 状态0 未开启 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;//状态0 未开启 1 开启
private String statusStr;//
private List<Role> roles;//
}
1.2 角色表
1.2.1 角色表信息描述role
序号 | 字段名称 | 字段类型 | 字段描述 |
---|---|---|---|
1 | id | varchar2 | 无意义,主键uuid |
2 | roleName | varchar2 | 角色名 |
3 | roleDesc | varchar2 | 角色描述 |
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<Permission> permissions;//权限资源与角色是多对多关系
private List<User> 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
序号 | 字段名称 | 字段类型 | 字段描述 |
---|---|---|---|
1 | id | varchar2 | 无意义,主键uuid |
2 | permissionName | varchar2 | 权限名 |
3 | url | varchar2 | 资源路径 |
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<Role> roles;//
}
1.3.4.权限资源与角色关联关系
权限资源与角色是多对多关系,我们使用role_permission表来描述。在实体类Permission中存在List,在Role类中有List
2.Spring Security概述
2.1 Spring Security介绍
Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。
官方文档 Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别
是使用领先的J2EE解决方案-Spring框架开发的企业软件项目。人们使用Spring Security有很多种原因,不过通常吸
引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。 特别要指出的是他们不能再
WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用
系统进行重新配 置安全。使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安
全特性。 安全包括两个主要操作
- “认证”,是为用户建立一个他所声明的主体。主题一般式指用户,设备或可以在你系 统中执行动作的其他系统。
- “授权”指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由 身份验证过程建立了。
Maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
</dependencies>
2.2 Spring Security使用
在pom.xml中加入maven依赖
配置web.xml文件加入过滤器
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
编写spring-security.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 配置不拦截的资源 -->
<security:http pattern="/login.jsp" security="none"/>
<security:http pattern="/failer.jsp" security="none"/>
<security:http pattern="/css/**" security="none"/>
<security:http pattern="/img/**" security="none"/>
<security:http pattern="/plugins/**" security="none"/>
<!--
配置具体的规则
auto-config="true" 不用自己编写登录的页面,框架提供默认登录页面
use-expressions="false" 是否使用SPEL表达式(没学习过)
-->
<security:http auto-config="true" use-expressions="false">
<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
<!-- 定义跳转的具体的页面 -->
<security:form-login
login-page="/login.jsp"
login-processing-url="/login.do"
default-target-url="/index.jsp"
authentication-failure-url="/failer.jsp"
authentication-success-forward-url="/pages/main.jsp"
/>
<!-- 关闭跨域请求 -->
<security:csrf disabled="true"/>
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />
</security:http>
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式
<security:password-encoder ref="passwordEncoder"/>-->
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!-- 提供了入门的方式,在内存中存入用户名和密码
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="{noop}admin" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
-->
</beans>
在web.xml中加入该配置文件的位置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:spring-security.xml</param-value>
</context-param>
2.3 使用数据库完成springSecurity用户登录流程分析
3.用户管理
3.1 用户登陆
用户管理的业务层接口需继承Spring Security框架提供的
UserDetailsService`接口
接口的实现类去实现loadUserByUsername(String username)
这个方法
返回类型为UserDetails
,可以new 一个Spring Security给我们提供的User类,把查到的对象的参数传过去
public class User implements UserDetails, CredentialsContainer {
private String password;
private final String username;
private final Set<GrantedAuthority> authorities;
private final boolean accountNonExpired; //帐户是否过期
private final boolean accountNonLocked; //帐户是否锁定
private final boolean credentialsNonExpired; //认证是否过期
private final boolean enabled; //帐户是否可用
}
3.1.1 Service
配置文件中提供的访问角色有access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"
所以要在User对象中设置角色名写一个方法getAuthority(List<Role> roles)
返回一个List集合,集合中装入的是角色描述与"ROLE_"拼接起来
还有判断当前用户的状态是开启还是未开启,其他参数暂时为true
使用User类的构造方法
public User(String username, String password, boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
System.out.println(username);
userInfo = userDao.findByUsername(username);
System.out.println(userInfo);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的用户对象封装成UserDetails
// User user=new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),getAuthority(userInfo.getRoles()));
User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 0 ? false : true, true, true, true, getAuthority(userInfo.getRoles()));
return user;
}
//作用就是返回一个List集合,集合中装入的是角色描述
public List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
List<SimpleGrantedAuthority> list = new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return list;
}
3.1.3.IUserDao
根据username去查询用户的详细信息,包括角色的信息,与角色表的关系是多对多
给IRoleDao用户id去users_role表查出对应的角色id,在用角色id从角色表中查出对应的角色信息
@Select("select * from users where username=#{username}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "email", column = "email"),
@Result(property = "password", column = "password"),
@Result(property = "phoneNum", column = "phoneNum"),
@Result(property = "status", column = "status"),
@Result(property = "roles",column = "id",javaType = java.util.List.class,many = @Many(select = "com.rgh.ssm.dao.IRoleDao.findRoleByUserId"))
})
public UserInfo findByUsername(String username) throws Exception;
IRoleDao
//根据用户id查询出所有对应的角色
@Select("select * from role where id in (select roleId from users_role where userId=#{userId})")
public List<Role> findRoleByUserId(String userId) throws Exception;
给数据库加入测试数据
insert into users values('111-222','tom@jj.com','tom','123','15265985479',1);
insert into role values('1111','ADMIN','vip');
insert into role values('2222','USER','vip');
insert into users_role values('111-222','1111');
insert into users_role values('111-222','2222');
3.2 用户退出
使用spring security完成用户退出,非常简单
-
配置
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success- url="/login.jsp" />
-
页面中
<a href="${pageContext.request.contextPath}/logout.do" class="btn btn-default btn-flat">注销</a>
3.3 用户查询
3.3.1.用户查询页面 user-list.jsp
<li id="system-setting">
<a href="${pageContext.request.contextPath}/user/findAll.do">
<i class="fa fa-circle-o"></i> 用户管理
</a>
</li>
3.3.2 UserController
//查询所有用户
@RequestMapping("/findAll.do")
public ModelAndView findAll()throws Exception{
ModelAndView mv = new ModelAndView();
List<UserInfo> userList = userService.findAll();
mv.addObject("userList",userList);
mv.setViewName("user-list");
return mv;
}
3.3.3 Dao
@Select("select * from user")
public List<UserInfo> findAll();
3.4 用户添加
3.4.1 用户添加界面user-add.jsp
onclick="location.href='${pageContext.request.contextPath}/pages/user-add.jsp'"
3.4.2 UserController
//用户添加
@RequestMapping("/save.do")
public String save(UserInfo userInfo) throws Exception {
userService.save(userInfo);
return "redirect:findAll.do";
}
3.4.3 Service
对用户的密码进行加密,Spring Security
提供了
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
使用它为用户的密码加密
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public void save(UserInfo userInfo) throws Exception {
//对密码进行加密处理
userInfo.setPassword(bCryptPasswordEncoder.encode(userInfo.getPassword()));
userDao.save(userInfo);
}
3.4.4 Dao
@Insert("insert into users(email,username,password,phoneNum,status) values(#{email},#{username},#{password},#{phoneNum},#{status})")
void save(UserInfo userInfo);
3.4.5 密码加密后登陆问题
Spring-Security.xml
中
<!-- 配置加密的方式-->
<security:password-encoder ref="passwordEncoder"/>
登陆时的service层不用再给密码前加"{noop}"
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的用户对象封装成UserDetails
// User user=new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),getAuthority(userInfo.getRoles()));
User user = new User(userInfo.getUsername(), userInfo.getPassword(), userInfo.getStatus() == 0 ? false : true, true, true, true, getAuthority(userInfo.getRoles()));
return user;
}
3.5 用户详情
3.5.1.用户详情页面user-show.jsp
注意需要添加JS
$("#collapse-table").treetable({
expandable : true
});
<table id="collapse-table"
class="table table-bordered table-hover dataTable">
<thead>
<tr>
<th>名称</th>
<th>描述</th>
</tr>
</thead>
页面展示
3.5.2.UserController
//查询指定id的用户
@RequestMapping("/findById.do")
public ModelAndView findById(String id)throws Exception{
ModelAndView mv = new ModelAndView();
UserInfo userInfo = userService.findById(id);
mv.addObject("user",userInfo);
mv.setViewName("user-show");
return mv;
}
3.5.3.Dao
用户的详细信息有用户信息,角色信息,权限信息他们之间的关系为
用户-角色:多对多,角色-权限:多对多,由user_role
,role_permission
两个关系表来建立关系
要通过userId把所有这个用户对应的角色和权限都查出来
插入权限的数据与角色建立关系,每次查到的数据都封装为实体类对象
insert into permission(permissionname,url) values ('user findAll','/user/findAll.do');
insert into permission(permissionname,url) values ('user findById','/user/findById.do');
insert into role_permission values('B2149C5A422C4D258ABF9617121CCD9F','1111');
insert into role_permission values('C797E3476F044FB4ABE52F446DDD6C96','1111');
insert into role_permission values('B2149C5A422C4D258ABF9617121CCD9F','2222');
3.5.3.1 IUserDao
把userId
给IRoleDao
查出对应的角色
@Select("select * from users where id=#{id}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "email", column = "email"),
@Result(property = "password", column = "password"),
@Result(property = "phoneNum", column = "phoneNum"),
@Result(property = "status", column = "status"),
@Result(property = "roles",column = "id",javaType = java.util.List.class,many = @Many(select = "com.rgh.ssm.dao.IRoleDao.findRoleByUserId"))
})
UserInfo findById(String id);
3.5.3.2 IRoleDao
通过users_role
表查出userId
对应的所有roleId
,并在role
表中查出
同时把查到的roleId
给IPermissionDao
,让它查出该角色下对应的权限
@Select("select * from role where id in (select roleId from users_role where userId=#{userId})")
@Results({
@Result(id = true,property = "id", column = "id"),
@Result(property = "roleName", column = "roleName"),
@Result(property = "roleDesc", column = "roleDesc"),
@Result(property = "permissions", column = "id",javaType = java.util.List.class,many = @Many(select = "com.rgh.ssm.dao.IPermissionDao.findPermissionByRoleId"))
})
public List<Role> findRoleByUserId(String userId) throws Exception;
3.5.3.3 IPermissionDao
把接到的roleId
通过role_permission表查到对应的permissionId
权限Id,再从permission
权限表中
查到对应的权限信息封装为实体类对象
@Select("select * from permission where id in (select permissionId from role_permission where roleId=#{id})")
public List<Permission> findPermissionByRoleId(String id)throws Exception;
3.5.4 页面数据显示
<div class="tab-pane" id="tab-treetable">
<table id="collapse-table"
class="table table-bordered table-hover dataTable">
<thead>
<tr>
<th>名称</th>
<th>描述</th>
</tr>
</thead>
<tr data-tt-id="0">
<td colspan="2">${user.username}</td>
</tr>
<tbody>
<c:forEach items="${user.roles}" var="role" varStatus="vs">
<tr data-tt-id="${vs.index+1}" data-tt-parent-id="0">
<td>${role.roleName }</td>
<td>${role.roleDesc }</td>
</tr>
<c:forEach items="${role.permissions}" var="permission">
<tr data-tt-id="1-1" data-tt-parent-id="${vs.index+1}">
<td>${permission.permissionName}</td>
<td>${permission.url}</td>
</tr>
</c:forEach>
</c:forEach>
</tbody>
</table>
</div>
4. 角色管理
4.1 角色查询
4.1.1.角色页面role-list.jsp
<li id="system-setting">
<a href="${pageContext.request.contextPath}/role/findAll.do">
<i class="fa fa-circle-o"></i> 角色管理</a>
</li>
4.1.2.RoleControlller
@RequestMapping("/findAll")
public ModelAndView findAll()throws Exception{
ModelAndView mv = new ModelAndView();
List<Role> roleList = roleService.findAll();
mv.addObject("roleList",roleList);
mv.setViewName("role-list");
return mv;
}
4.1.3.Dao
@Select("select * from role")
public List<Role> findAll();
4.2 角色添加
4.2.1.角色添加页面role-add.jsp
onclick="location.href='${pageContext.request.contextPath}/pages/role-add.jsp'"
<form action="${pageContext.request.contextPath}/role/save.do">
4.2.2.RoleControlller
//添加角色
@RequestMapping("/save.do")
public String save(Role role)throws Exception{
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
<li id="system-setting">
<a href="${pageContext.request.contextPath}/permission/findAll.do"> <i class="fa fa-circle-o"></i> 资源权限管理</a>
</li>
5.1.2.PermissionController
@RequestMapping("/findAll.do")
public ModelAndView findAll()throws Exception{
ModelAndView mv = new ModelAndView();
List<Permission> permissionList = permissionService.findAll();
mv.addObject("permissionList",permissionList);
mv.setViewName("permission-list");
return mv;
}
5.1.3.Dao
@Select("select * from permission")
public List<Permission> findAll();
5.1.4 页面展示
<c:forEach items="${permissionList}" var="p">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${p.id }</td>
<td>${p.permissionName }</td>
<td>${p.url }</td>
<td class="text-center">
<a href="${pageContext.request.contextPath}/role/findById.do?id=${p.id}" class="btn bg-olive btn-xs">详情</a>
<a href="${pageContext.request.contextPath}/user/findUserByIdAndAllRole.do?id=${p.id}" class="btn bg-olive btn-xs">添加角色</a>
</td>
</tr>
</c:forEach>
5.2 资源权限添加
5.2.1.权限资源添加页面permission-add.jsp
onclick="location.href='${pageContext.request.contextPath}/pages/permission-add.jsp'"
<form action="${pageContext.request.contextPath}/permission/save.do"
method="post">
5.2.2.PermissionController
@RequestMapping("/save.do")
public String save(Permission permission)throws Exception{
permissionService.save(permission);
return "redirect:findAll.do";
}
5.2.3.Dao
@Insert("insert into permission(permissionName,url) values(#{permissionName},#{url})")
void save(Permission permission);
6.权限关联与控制
6.1 用户角色关联
用户与角色之间是多对多关系,我们要建立它们之间的关系,只需要在中间表user_role插入数据即可。
6.1.1. 用户角色关联相关页面
-
user-list.jsp中
<a href="${pageContext.request.contextPath}/user/findUserByIdAndAllRole.do?id=${user.id}" class="btn bg-olive btn-xs">添加角色</a>
-
展示可以添加角色的页面user-roe-add.jsp
6.1.2.UserController
-
findUserByIdAndAllRole(@RequestParam(name="id",required = true)String userid)方法
此方法用于查找要操作的用户及可以添加的角色,参数是要操作的用户id
@RequestMapping("/findUserByIdAndAllRole.do") public ModelAndView findUserByIdAndAllRole(@RequestParam(name="id",required = true)String userid)throws Exception{ ModelAndView mv = new ModelAndView(); //1.根据id查询用户 UserInfo userInfo = userService.findById(userid); //2.根据用户id查询可以添加的角色 List<Role> otherRoles = userService.findOtherRoles(userid); mv.addObject("user",userInfo); mv.addObject("roleList",otherRoles); mv.setViewName("user-role-add"); return mv; }
IUserService的findById方法获取要操作的User
调用IRoleService的findOtherRole方法用于获取可以添加的角色信息
-
addRoleToUser(@RequestParam(name="userId",required = true) String userId,@RequestParam(name="ids",required = true)String[] roleIds )
方法此方法用于在用户与角色之间建立关系,参数userId代表要操作的用户id,参数ids代表的是角色id数组
//给用户添加角色 @RequestMapping("/addRoleToUser.do") public String addRoleToUser(@RequestParam(name="userId",required = true) String userId,@RequestParam(name="ids",required = true)String[] roleIds ){ userService.addRoleToUser(userId,roleIds); return "redirect:findAll.do"; }
6.1.3 UserService
通过userid
查找这个用户没有的角色
public List<Role> findOtherRoles(String userid) throws Exception {
return userDao.findOtherRoles(userid);
}
通过userid
和roleId
为当前用户添加角色,这里角色id是个数组,所以遍历去调用userDao.add
public void addRoleToUser(String userId, String[] roleIds) {
for(String roleId:roleIds){
userDao.addRoleToUser(userId,roleId);
}
}
6.1.4 UserDao
通过userid
从users_role
表中查出这个用户拥有的角色id,通过角色id从role
表中查出它没有的角色
用于查找可以添加的角色
@Select("select * from role where id not in (select roleId from users_role where userId=#{userId})")
List<Role> findOtherRoles(String userid);
通过userId
和roleId
在user_role
中添加用户与角色关系
@Insert("insert into users_role(userId,roleId) values(#{userId},#{roleId})")
void addRoleToUser(@Param("userId") String userId, @Param("roleId") String roleId);
方法中有多个参数要给参数前加上@Param("")
6.2 角色权限关联
角色与权限之间是多对多关系,我们要建立它们之间的关系,只需要在中间表role_permission插入数据即可。
6.2.1. 角色权限关联相关页面
-
在role-list.jsp页面上添加链接
<a href="${pageContext.request.contextPath}/role/findRoleByIdAndAllPermission.do?id=${role.id}" class="btn bg-olive btn-xs">添加权限</a>
-
展示可以添加权限的页面roe-permission-add.jsp
6.2.2.RoleController
-
findRoleByIdAndAllPermission(@RequestParam(name="id",required = true) String roleId)
方法此方法用于查找要操作的角色及可以添加的权限,参数是要操作的角色id
//根据roleId查询role并查看角色可以添加的权限 @RequestMapping("/findRoleByIdAndAllPermission.do") public ModelAndView findRoleByIdAndAllPermission(@RequestParam(name="id",required = true) String roleId)throws Exception{ ModelAndView mv = new ModelAndView(); //根据roleId查询role Role role = roleService.findById(roleId); //根据roleId查询可以添加的权限 List<Permission> otherPermission = roleService.findOtherPermissions(roleId); mv.addObject("role",role); mv.addObject("permissionList",otherPermission); mv.setViewName("role-permission-add"); return mv; }
调用IRoleService的findById方法获取要操作的Role
调用IPermissionService的findOtherPermission方法用于获取可以添加的权限信息 -
public String addPermissionToRole(@RequestParam(name = "roleId", required = true) String roleId, @RequestParam(name = "ids", required = true) String[] permissionIds)
方法此方法用于在角色与权限之间建立关系,参数roleId代表要操作的角色id,参数permissionIds代表的是权限id数组
@RequestMapping("/addPermissionToRole.do") public String addPermissionToRole(@RequestParam(name = "roleId", required = true) String roleId, @RequestParam(name = "ids", required = true) String[] permissionIds) throws Exception { roleService.addPermissionToRole(roleId, permissionIds); return "redirect:findAll.do"; }
6.2.3 IRoleDao
用于查找可以添加的权限
@Select("select * from permission where id not in (select permissionId from role_permission where roleId=#{roleId})")
List<Permission> findOtherPermissions(String roleId);
用于绑定角色与权限的关系
@Insert("insert into role_permission(roleId,permissionId) values(#{roleId},#{permissionId})")
void addPermissionToRole(@Param("roleId") String roleId, @Param("permissionId") String permissionId);
6.3 服务器端方法级权限控制
在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要单独通过global-method-security元素的对应属性进行启用
6.3.1.开启注解使用
-
配置文件
<security:global-method-security jsr250-annotations="enabled"/> <security:global-method-security secured-annotations="enabled"/> <security:global-method-security pre-post-annotations="disabled"/>
-
注解开启
@EnableGlobalMethodSecurity :Spring Security默认是禁用注解的,要想开启注解,需要在继承WebSecurityConfigurerAdapter的类上加@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导入
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>version</version> </dependency>
-
页面导入
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
6.4.2.常用标签
在jsp中我们可以使用以下三种标签,其中authentication代表的是当前认证对象,可以获取当前认证对象信息,例如用户名。其它两个标签我们可以用于权限控制
6.4.2.1 authentication
<security:authentication property="" htmlEscape="" scope="" var=""/>
- property: 只允许指定Authentication所拥有的属性,可以进行属性的级联获取,如“principle.username”,不允许直接通过方法进行调用
- htmlEscape:表示是否需要将html进行转义。默认为true。
- scope:与var属性一起使用,用于指定存放获取的结果的属性名的作用范围,默认我pageContext。Jsp中拥有的作用范围都进行进行指定
- var: 用于指定一个属性名,这样当获取到了authentication的相关信息后会将其以var指定的属性名进行存放,默认是存放在pageConext中
6.4.2.2 authorize
authorize是用来判断普通权限的,通过判断用户是否具有对应的权限而控制其所包含内容的显示
<security:authorize access="" method="" url="" var=""></security:authorize>
- access: 需要使用表达式来判断权限,当表达式的返回结果为true时表示拥有对应的权限
- method:method属性是配合url属性一起使用的,表示用户应当具有指定url指定method访问的权限,method的默认值为GET,可选值为http请求的7种方法
- url:url表示如果用户拥有访问指定url的权限即表示可以显示authorize标签包含的内容
- var:用于指定将权限鉴定的结果存放在pageContext的哪个属性中
6.4.2.3 accesscontrollist
accesscontrollist标签是用于鉴定ACL权限的。其一共定义了三个属性:hasPermission、domainObject和var,其中前两个是必须指定的
<security:accesscontrollist hasPermission="" domainObject="" var="">/security:accesscontrollist>
- hasPermission:hasPermission属性用于指定以逗号分隔的权限列表
- domainObject:domainObject用于指定对应的域对象
- var:var则是用以将鉴定的结果以指定的属性名存入pageContext中,以供同一页面的其它地方使用