本章内容简介
- Spring Security的简介、入门使用和自定义使用
- 密码加密
- 用户管理(查询所有用户,查询用户详情,添加用户)
- 角色管理(查询所有角色,查询角色详情,添加角色)
- 权限管理(查询所有权限,添加权限)
- 权限关联与控制(用户关联角色、角色关联权限、服务器端方法级权限控制、页面端标签控制权限)
数据库、表结构与实体类
用户表users
users表信息描述
创建表和插入数据的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
)
insert into users values('111','jack@cncs.com','jack','jack','12345678901',1);
select * from users;
update users set password='$2a$10$TFWvT2qn43/2xtLScpU4ZeZY/zNj75gVcKnR5dZD4BTh.ugemxg.2' where id='111';
users表的实体类UserInfo
//用户的实体类,对应数据库中users表
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<Role> roles;
}
角色表role
表信息描述
创建表和插入数据的sql语句
CREATE TABLE role(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
roleName VARCHAR2(50) ,
roleDesc VARCHAR2(50)
)
insert into role values('r-111','USER','NORMOL PERMISSION');
insert into role values('r-222','ADMIN','HIGH PERMISSION');
select * from role;
Role实体类
public class Role {
private String id;
private String roleName;
private String roleDesc;
private List<Permission> permissions;
private List<UserInfo> users;
}
权限资源permission
表信息描述
创建表和插入数据的sql语句
CREATE TABLE permission(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
permissionName VARCHAR2(50) ,
url VARCHAR2(50)
)
insert into permission(permissionName,url) values('user findById','/user/findById');
insert into permission(permissionName,url) values('user findAll','/user/findAll');
update permission set url='/user/findById.do' where id='5DFBCF7A62284E80BB244212F5DCC4B5';
update permission set url='/user/findAll.do' where id='899BE8709E6349E998E3361392B36B63';
select * from permission;
==5DFBCF7A62284E80BB244212F5DCC4B5
==899BE8709E6349E998E3361392B36B63
Permission实体类
public class Permission {
private String id;
private String permissionName;
private String url;
private List<Role> roles;
}
用户–角色中间表users_role
表信息描述
一个用户可以有多个角色,一个角色也可以有多个用户,它们的关系为多对多。
创建表和插入数据的sql语句
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)
)
insert into users_role values('111','r-111');
insert into users_role values('111','r-222');
insert into users_role values('F39890D41F8A4BDDB4F392454C695A07','r-111');
select * from users_role;
select * from role where id in(select roleId from users_role where userId='111')
角色–权限表role_promission
表信息描述
一个角色可以有多个权限,一个权限可以属于多个角色,它们的关系为多对多。
创建表和插入数据的sql语句
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)
)
insert into role_permission values('5DFBCF7A62284E80BB244212F5DCC4B5','r-222');
insert into role_permission values('899BE8709E6349E998E3361392B36B63','r-222');
insert into role_permission values('899BE8709E6349E998E3361392B36B63','r-111');
select * from role_permission;
Spring Security
概述
Spring Security是一个灵活和强大的身份验证和访问控制框架,以确保基于Spring的Java Web应用程序的安全。
Spring Security是一个轻量级的安全框架,它确保基于Spring的应用程序提供身份验证和授权支持。它与Spring MVC有很好地集成,并配备了流行的安全算法实现捆绑在一起。
【易百教程】Spring Security教程:https://www.yiibai.com/spring-security/
快速入门
pom.xml中引入依赖
<properties>
<spring.security.version>5.0.1.RELEASE</spring.security.version>
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
编辑spring-security.xml
在【ssm_eams_web】的resources目录下新建并配置文件spring-security.xml。
下面的配置开启了自动配置登录页面,需要使用USER_ROLE
的权限。这里只是演示spring security的入门使用。
- 使用这个
<security:authentication-manager>
标签,作用:手动配置登录的用户名&密码,登录权限。 - 使用了
auto-config="true"
,自动配置登录页面。
<?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 security="none" pattern="/login.html"/>
<security:http security="none" pattern="/failer.html"/>
<security:http auto-config="true" use-expressions="false">
<!-- 配置资料连接,表示任意路径都需要ROLE_USER权限 -->
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<!-- 自定义登陆页面,login-page 自定义登陆页面 authentication-failure-url 用户权限校验失败之后才会跳转到这个页面,如果数据库中没有这个用户则不会跳转到这个页面。
default-target-url 登陆成功后跳转的页面。 注:登陆页面用户名固定 username,密码 password,action:login -->
<security:form-login login-page="/login.html"
login-processing-url="/login" username-parameter="username"
password-parameter="password" authentication-failure-url="/failer.html"
default-target-url="/success.html" authentication-success-forward-url="/success.html"
/>
<!-- 关闭CSRF,默认是开启的 -->
<security:csrf disabled="true"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="user" password="{noop}user"
authorities="ROLE_USER"/>
<security:user name="admin" password="{noop}admin"
authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
配置web.xml
springSecurityFilterChain
这个滤波器名称固定
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>SpringSecurity314</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
使用Spring Security完成用户登录
(1)修改spring-security.xml
修改security:intercept-url
标签内容为
- 表示有这两个角色的用户才能访问
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
将<security:authentication-manager>
标签内容修改为
- 使用自定义的userService来进行用户登录验证
<!--切换成数据库中的用户名和密码-->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
</security:authentication-provider>
</security:authentication-manager>
(2)创建IUserService接口
- 它必须继承UserDetailsService接口
- UserDetailsService接口中有一个方法
UserDetails loadUserByUsername(String username)
。
public interface IUserService extends UserDetailsService {
}
(3)创建UserServiceImpl实现类
- 实现这个方法时,注意通过构造方法实例化User对象时,需要给它传入参数
{noop}
必须加上,因为此时密码没有加密- 传入的第三个参数需要一个
List<GrantedAuthority>
类型的集合。 - 在
getAuthority()
中需要将角色字符串补全。
//使用spring-security进行登录验证
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo=null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的UserInfo对象,封装到UserDetails中,注:User是UserDetails的实现类。
User user=new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),getAuthority());
return user;
}
//获取权限集合
private List<GrantedAuthority> getAuthority(List<Role> roles){
List<GrantedAuthority> list=new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
}
return list;
}
用户退出注销
在spring-security.xml中的</security:http>
标签中添加以下内容
<!--用户注销 会清除session-->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp"/>
用户管理
需求
- 查看用户列表
- 查询用户详情(用户信息users,用户拥有的角色role,角色拥有的权限promission)
- 添加用户
查看用户列表
查询所有用户流程
每一步流程的部分代码
UserController
//查询所有用户
@RequestMapping("/findAll.do")
//@Secured("ROLE_ADMIN")
public ModelAndView findAll() {
ModelAndView mv = new ModelAndView();
List<UserInfo> userInfoList = userService.findAll();
mv.addObject("userList", userInfoList);
mv.setViewName("user-list");
return mv;
}
UserService
@Override
public List<UserInfo> findAll() {
return userDao.findAll();
}
UserDao
@Select("select * from users")
List<UserInfo> findAll();
user-list.jsp
<thead>
<tr>
<th class="" style="padding-right: 0px"><input
id="selall" type="checkbox" class="icheckbox_square-blue">
</th>
<th class="sorting_asc">ID</th>
<th class="sorting_desc">用户名</th>
<th class="sorting_asc sorting_asc_disabled">邮箱</th>
<th class="sorting_desc sorting_desc_disabled">联系电话</th>
<th class="sorting">状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${userList}" var="user">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${user.id }</td>
<td>${user.username }</td>
<td>${user.email }</td>
<td>${user.phoneNum }</td>
<td>${user.statusStr }</td>
<td class="text-center">
<a href="${pageContext.request.contextPath}/user/findById.do?id=${user.id}" class="btn bg-olive btn-xs">详情</a>
<a href="${pageContext.request.contextPath}/user/findUserAndAllRoleById.do?id=${user.id}" class="btn bg-olive btn-xs">添加角色</a>
</td>
</tr>
</c:forEach>
</tbody>
查询所有用户效果图
查询用户详情
查询用户详情流程
UserController
//根据id查寻用户详情
@RequestMapping("/findById.do")
//@PreAuthorize("hasAuthority('ADMIN')")
public ModelAndView findById(@RequestParam(name = "id", required = true) String id) {
ModelAndView mv = new ModelAndView();
UserInfo userInfo = userService.findById(id);
mv.addObject("user", userInfo);
mv.setViewName("user-show");
return mv;
}
UserService
//根据id查询用户
@Override
public UserInfo findById(String id) {
return userDao.findById(id);
}
UserDao
//根据id查询用户
@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.cncs.dao.IRoleDao.findRoleByUserId")),
})
UserInfo findById(String id);
user-show.jsp
<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>
查询用户详情效果图
添加用户
添加用户流程
UserController
@RequestMapping("/save.do")
public String save(UserInfo userInfo) {
userService.save(userInfo);
return "redirect:findAll.do";
}
UserService
@Override
public void save(UserInfo userInfo) {
userDao.save(userInfo);
}
UserDao
@Insert("insert into users(email,username,password,phoneNum,status) values(#{email},#{username},#{password},#{phoneNum},#{status})")
void save(UserInfo userInfo);
user-add.jsp
<form action="${pageContext.request.contextPath}/user/save.do"
method="post">
<!-- 正文区域 -->
<section class="content"> <!--产品信息-->
<div class="panel panel-default">
<div class="panel-heading">用户信息</div>
<div class="row data-type">
<div class="col-md-2 title">用户名称</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="username"
placeholder="用户名称" value="">
</div>
<div class="col-md-2 title">密码</div>
<div class="col-md-4 data">
<input type="password" class="form-control" name="password"
placeholder="密码" value="">
</div>
<div class="col-md-2 title">邮箱</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="email"
placeholder="邮箱" value="">
</div>
<div class="col-md-2 title">联系电话</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="phoneNum"
placeholder="联系电话" value="">
</div>
<div class="col-md-2 title">用户状态</div>
<div class="col-md-4 data">
<select class="form-control select2" style="width: 100%"
name="status">
<option value="0" selected="selected">关闭</option>
<option value="1">开启</option>
</select>
</div>
</div>
</div>
<!--订单信息/--> <!--工具栏-->
<div class="box-tools text-center">
<button type="submit" class="btn bg-maroon">保存</button>
<button type="button" class="btn bg-default"
onclick="history.back(-1);">返回</button>
</div>
<!--工具栏/--> </section>
<!-- 正文区域 /-->
</form>
添加用户效果图
对新增用户的密码进行加密
(1)sring-security.xml中修改配置
<!--切换成数据库中的用户名和密码-->
<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"/>
ps:BCryptPasswordEncoder
可以单独配置到一个工具类
(2)在UserService实现类中使用
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public void save(UserInfo userInfo) {
//对密码进行加密
String password= bCryptPasswordEncoder.encode(userInfo.getPassword());
userInfo.setPassword(password);
userDao.save(userInfo);
}
加密后的密码示例:
$2a 10 10 10ZSCmtVzkvviYBrqmv/iC0ebls2OacbjM8xPfbDKSpT2rtgy.o27YW
(3)修改loadUserByUsername()
方法,让其可以使用加密后密码进行登录。
//使用spring-security进行登录验证
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo=null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的UserInfo对象,封装到UserDetails中,注:User是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;
}
角色管理
需求
- 查看所有角色
- 添加角色
查看所有角色
查询所有角色流程
每一步流程的部分代码
RoleController
//查询所有角色
@RequestMapping("/findAll.do")
public ModelAndView findAll() {
ModelAndView mv = new ModelAndView();
List<Role> roles = roleService.findAll();
mv.addObject("roleList",roles);
mv.setViewName("role-list");
return mv;
}
RoleService
@Override
public List<Role> findAll() {
return roleDao.findAll();
}
RoleDao
//查询所有角色
@Select("select * from role")
List<Role> findAll();
role-list.jsp
<c:forEach items="${roleList}" var="role">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${role.id }</td>
<td>${role.roleName }</td>
<td>${role.roleDesc }</td>
<td class="text-center">
<a href="${pageContext.request.contextPath}/role/findById.do?id=${role.id}" class="btn bg-olive btn-xs">详情</a>
<a href="${pageContext.request.contextPath}/role/findRoleAndPermissionsById.do?id=${role.id}" class="btn bg-olive btn-xs">添加权限</a>
</td>
</tr>
</c:forEach>
效果展示
添加角色
添加角色流程图
每一步流程的部分代码
RoleController
@RequestMapping("/save.do")
public String save(Role role){
roleService.save(role);
return "redirect:findAll.do";
}
RoleService
@Override
public void save(Role role) {
roleDao.save(role);
}
RoleDao
//保存角色
@Insert("insert into role(roleName,roleDesc) values(#{roleName},#{roleDesc})")
void save(Role role);
role-add.jsp
<form action="${pageContext.request.contextPath}/role/save.do"
method="post">
<!-- 正文区域 -->
<section class="content"> <!--产品信息-->
<div class="panel panel-default">
<div class="panel-heading">角色信息</div>
<div class="row data-type">
<div class="col-md-2 title">角色名称</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="roleName"
placeholder="角色名称" value="">
</div>
<div class="col-md-2 title">角色描述</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="roleDesc"
placeholder="角色描述" value="">
</div>
</div>
</div>
<!--订单信息/--> <!--工具栏-->
<div class="box-tools text-center">
<button type="submit" class="btn bg-maroon">保存</button>
<button type="button" class="btn bg-default"
onclick="history.back(-1);">返回</button>
</div>
<!--工具栏/--> </section>
<!-- 正文区域 /-->
</form>
效果展示
资源权限管理
需求
- 查询所有权限
- 添加权限
查询所有资源权限
部分代码
PermissionController
@RequestMapping("/findAll.do")
public ModelAndView findAll(){
ModelAndView mv = new ModelAndView();
List<Permission> permissions= permissionService.findAll();
mv.addObject("permissionList", permissions);
mv.setViewName("permission-list");
return mv;
}
PermissionService
@Override
public List<Permission> findAll() {
return permissionDao.findAll();
}
PermissionDao
@Select("select * from permission")
List<Permission> findAll();
permission.jsp
<c:forEach items="${permissionList}" var="permission">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${permission.id }</td>
<td>${permission.permissionName }</td>
<td>${permission.url }</td>
<td class="text-center">
<a href="${pageContext.request.contextPath}/permission/findById.do?id=${permission.id}" class="btn bg-olive btn-xs">详情</a>
<a href="${pageContext.request.contextPath}/permission/findUserByIdAndAllRole.do?id=${permission.id}" class="btn bg-olive btn-xs">添加角色</a>
</td>
</tr>
</c:forEach>
效果展示
添加权限
部分代码
PermissionController
@RequestMapping("/save.do")
public String save(Permission permission){
permissionService.save(permission);
return "forward:findAll.do";
}
PermissionService
@Override
public void save(Permission permission) {
permissionDao.save(permission);
}
PermissionDao
@Insert("insert into permission(permissionName,url) values(#{permissionName},#{url})")
void save(Permission permission);
permission-add.jsp
<form action="${pageContext.request.contextPath}/permission/save.do"
method="post">
<!-- 正文区域 -->
<section class="content"> <!--产品信息-->
<div class="panel panel-default">
<div class="panel-heading">资源权限信息</div>
<div class="row data-type">
<div class="col-md-2 title">权限名称</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="permissionName"
placeholder="权限名称" value="">
</div>
<div class="col-md-2 title">URL</div>
<div class="col-md-4 data">
<input type="text" class="form-control" name="url"
placeholder="URL" value="">
</div>
</div>
</div>
<!--订单信息/--> <!--工具栏-->
<div class="box-tools text-center">
<button type="submit" class="btn bg-maroon">保存</button>
<button type="button" class="btn bg-default"
onclick="history.back(-1);">返回</button>
</div>
<!--工具栏/--> </section>
<!-- 正文区域 /-->
</form>
效果展示
用户关联角色
一个用户可以有多个角色,这里的系统,存在三个角色包括:ADMIN,USER,GUEST。
需求
- 为用户添加他没有的角色
添加角色
为用户添加角色流程图
部分代码
(1)查询用户信息&用户没有的角色
UserController
@RequestMapping("/findUserAndAllRoleById.do")
public ModelAndView findUserAndAllRoleById(@RequestParam(name = "id", required = true) String id) {
ModelAndView mv = new ModelAndView();
//根据id查找用户
UserInfo userInfo = userService.findById(id);
mv.addObject("user", userInfo);
//根据userId查找用户没有的角色
List<Role> roles = roleService.findOtherRolesByUserId(id);
mv.addObject("roleList", roles);
mv.setViewName("user-role-add");
return mv;
}
UserService
@Override
public UserInfo findById(String id) {
return userDao.findById(id);
}
@Override
public List<Role> findOtherRolesByUserId(String userId) {
return roleDao.findOtherRolesByUserId(userId);
}
UserDao
@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.cncs.dao.IRoleDao.findRoleByUserId")),
})
UserInfo findById(String id);
@Select("select * from role where id not in(select roleId from users_role where userId=#{userId})")
List<Role> findOtherRolesByUserId(String userId);
user-role-add.jsp
- 通过隐藏域传递user的id
<form
action="${pageContext.request.contextPath}/user/addRoleToUser.do"
method="post">
<!-- 正文区域 -->
<section class="content">
<input type="hidden" name="userId" value="${user.id}">
<table id="dataList"
class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class="" style="padding-right: 0px">
<input id="selall"
type="checkbox" class="icheckbox_square-blue"></th>
<th class="sorting_asc">ID</th>
<th class="sorting">角色名称</th>
<th class="sorting">角色描述</th>
</tr>
</thead>
<tbody>
<c:forEach items="${roleList}" var="role">
<tr>
<td>
<input name="ids" type="checkbox" value="${role.id}">
</td>
<td>${role.id}</td>
<td>${role.roleName }</td>
<td>${role.roleDesc}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!--订单信息/--> <!--工具栏-->
<div class="box-tools text-center">
<button type="submit" class="btn bg-maroon">保存</button>
<button type="button" class="btn bg-default"
onclick="history.back(-1);">返回</button>
</div>
<!--工具栏/--> </section>
<!-- 正文区域 /-->
</form>
效果展示
(2)添加角色(上一步执行完毕会进入这一步)
UserController
//为用户添加角色
@RequestMapping("/addRoleToUser.do")
public String addRoleToUser(@RequestParam(name = "userId") String userId, @RequestParam(name = "ids", required = true) String[] ids) {
userService.addRoleToUser(userId,ids);
return "forward:findAll.do";
}
UserService
//为用户添加角色
@Override
public void addRoleToUser(String userId, String[] ids) {
//通过遍历添加所有角色
for (String roleId : ids) {
userDao.addRoleToUser(userId,roleId);
}
}
UserDao
//添加角色
//@Param参数,用于指定多个参数类型一致时,使用名称区分。
@Insert("insert into users_role(userId,roleId) values(#{userId},#{roleId})")
void addRoleToUser(@Param("userId") String userId,@Param("roleId") String roleId);
角色关联权限
这里流程和用户关联角色一致,不多赘述。
服务器端方法级权限控制
在服务器端可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要单独通过global-method-security元素的对应属性进行启用。
想要使用这三个注解,需要在spring-security.xml中开启访问权限控制。
<!--开启访问权限控制-->
<security:global-method-security jsr250-annotations="enabled"/>
<security:global-method-security secured-annotations="enabled"/>
<security:global-method-security pre-post-annotations="enabled"/>
JSR-250注解的使用
- @RolesAllowed({“USER”, “ADMIN”}) 该方法只要具有"USER", "ADMIN"任意一种权限就可以访问。这里可以省略前缀ROLE_,实际的权限可能是ROLE_ADMIN
- @PermitAll表示允许所有的角色进行访问,也就是说不进行权限控制
- @DenyAll是和PermitAll相反的,表示无论什么角色都不能访问
例一:
//@RolesAllowed({"USER","ADMIN"})
@RequestMapping("/findAll.do")
public ModelAndView findAll(){
ModelAndView mv = new ModelAndView();
List<Product> list = productService.findAll();
//System.out.println(list);
mv.addObject("productList",list);
mv.setViewName("product-list");
return mv;
}
@Secured注解的使用
@Secured注解标注的方法进行权限控制的支持,其值默认为disabled。
例一:
@Secured("ROLE_ADMIN")
public ModelAndView findAll() {
ModelAndView mv = new ModelAndView();
List<UserInfo> userInfoList = userService.findAll();
mv.addObject("userList", userInfoList);
mv.setViewName("user-list");
return mv;
}
支持表达式的注解的使用
-
@PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
示例:
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)") void changePassword(@P("userId") long userId ){ } 这里表示在changePassword方法执行之前,判断方法参数userId的值是否等于principal中保存的当前用户的 userId,或者当前用户是否具有ROLE_ADMIN权限,两种符合其一,就可以访问该方法。
@PreAuthorize("hasAuthority('ADMIN')") public ModelAndView findById(@RequestParam(name = "id", required = true) String id) {}
-
@PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
示例:
@PostAuthorize User getUser("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')");
-
@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
-
@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
页面端标签控制权限
在jsp页面中可以使用spring security提供的权限标签来进行权限控制。
pom.xml中引入依赖
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>version</version>
</dependency>
jsp页面导入
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
在jsp中可以使用以下三种标签,其中authentication代表的是当前认证对象,可以获取当前认证对象信息,例如用户名。其它两个标签可以用于权限控制。
authentication
- property:只允许指定Authentication所拥有的属性,可以进行属性的级联获取,如“principle.username”,不允许直接通过方法进行调用htmlEscape:表示是否需要将html进行转义。默认为true。
- scope:与var属性一起使用,用于指定存放获取的结果的属性名的作用范围,默认为pageContext。Jsp中拥有的作用范围都进行进行指定
- var:用于指定一个属性名,这样当获取到了authentication的相关信息后会将其以var指定的属性名进行存放,默认是存放在pageConext中
示例:
<security:authentication property="principal.username" />
authorize
在页面中进行权限控制
注意,使用该标签,需要在spring-security.xml中开启对SPEL表达式的支持,同时需要将访问的角色也修改为表达式
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
示例(标签中的内容只有拥有ADMIN角色的用户才能看见):
<security:authorize access="hasRole('ROLE_ADMIN')">
<li id="system-setting">
<a href="${pageContext.request.contextPath}/user/findAll.do">
<i class="fa fa-circle-o"></i> 用户管理
</a>
</li>
</security:authorize>
accesscontrollist
accesscontrollist标签是用于鉴定ACL权限的。其一共定义了三个属性:hasPermission、domainObject和var,其中前两个是必须指定的
<security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist>
- hasPermission:用于指定以逗号分隔的权限列表
- domainObject:用于指定对应的域对象
- var:用以将鉴定的结果以指定的属性名存入pageContext中,以供同一页面的其它地方使用