企业权限系统_3权限操作

SSM权限操作

1. 数据库与表结构

1.1 用户表

1.1.1 用户表信息描述users

序号 字段名称 字段类型 字段描述
1 id varchar2 无意义,主键uuid
2 email 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

userIdIRoleDao查出对应的角色

@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表中查出

同时把查到的roleIdIPermissionDao,让它查出该角色下对应的权限

@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);
}

通过useridroleId为当前用户添加角色,这里角色id是个数组,所以遍历去调用userDao.add

public void addRoleToUser(String userId, String[] roleIds) {
  for(String roleId:roleIds){
    userDao.addRoleToUser(userId,roleId);
  }
}
6.1.4 UserDao

通过useridusers_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);

通过userIdroleIduser_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中,以供同一页面的其它地方使用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容