企业权限管理系统第5章--权限操作

本章内容简介

  • 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中,以供同一页面的其它地方使用
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值