尚好房 10_Spring Security

尚好房:Spring Security

一、Spring Security概念

前面我们已经完成了尚好房权限管理的部分相关功能,给用户分配角色,给角色分配权限,及左侧动态菜单,做好权限管理的数据准备,接下来我们要使用这些数据进行权限的相关控制。

1、认证和授权概念

现在我们需要思考2个问题:

*问题1*:在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗?

答案显然是否定的,要操作这些功能必须首先登录到系统才可以。

*问题2*:是不是所有用户,只要登录成功就都可以操作所有功能呢?

答案是否定的,并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限,这就需要进行授权了。(用户登录之后,对每个用户进行授权,通过授权去访问系统中不同的功能–>授权)

*认证*:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。

*授权*:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。

本章节就是要对后台系统进行权限控制,其本质就是对用户进行认证和授权。

2、Spring Security简介

Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我们来简化认证和授权的过程。

官网:https://spring.io/projects/spring-security/

中文官网:https://www.w3cschool.cn/springsecurity/

尚好房 10_Spring Security_第1张图片

对应的maven坐标:


<dependency>
    <groupId>org.springframework.securitygroupId>
    <artifactId>spring-security-webartifactId>
    <version>5.2.7.RELEASEversion>
dependency>
<dependency>
    <groupId>org.springframework.securitygroupId>
    <artifactId>spring-security-configartifactId>
    <version>5.2.7.RELEASEversion>
dependency>

常用的权限框架除了Spring Security,还有Apache的shiro框架。

二、Spring Security集成入门

目标: 让用户访问管理后台中的资源的时候,需要输入用户名和密码进行登录

1、引入依赖

1.1、shf-parent添加版本管理

pom.xml

<spring.security.version>5.2.7.RELEASEspring.security.version>

<dependency>
    <groupId>org.springframework.securitygroupId>
    <artifactId>spring-security-webartifactId>
    <version>${spring.security.version}version>
dependency>
<dependency>
    <groupId>org.springframework.securitygroupId>
    <artifactId>spring-security-configartifactId>
    <version>${spring.security.version}version>
dependency>

1.2、web-admin引入依赖

目前只是我们的后台管理系统需要授权与认证

pom.xml

<dependencies>
    
    <dependency>
        <groupId>org.springframework.securitygroupId>
        <artifactId>spring-security-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.securitygroupId>
        <artifactId>spring-security-configartifactId>
    dependency>
dependencies>

2、配置Spring Security Fillter

web.xml



<filter>
  <filter-name>springSecurityFilterChainfilter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
  <filter-name>springSecurityFilterChainfilter-name>
  <url-pattern>/*url-pattern>
filter-mapping>

3、配置Spring Security

配置Spring Security有两种方式:

​ 1、xml文件配置

​ 2、java类配置

两种方式配置效果一致,当前我们使用java类配置,更加简洁,我们在web-admin项目中创建com.atguigu.config.WebSecurityConfig

package com.atguigu.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;


@Configuration
@EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

}

4、测试

仅需三个步骤,我们就已经集成好了Spring Security,其他的事情就可以交给Spring Security为我们处理。

启动项目

访问:http://localhost:8000/

尚好房 10_Spring Security_第2张图片

所有资源访问受限(包括静态资源)

url自动跳转到了一个默认的登录页面(框架自带的),我们目前没有定义login页面及login controller方法。

但是当前没有账号啊!下面我们测试一个最简单的内存分配用户名密码。

4.1、内存分配用户名密码

操作类:WebSecurityConfig

重写configure(AuthenticationManagerBuilder auth)方法

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("lucy")
            .password(new BCryptPasswordEncoder().encode("123456"))
            .roles("");

}

请求:http://localhost:8000/

报错:springsecurity There is no PasswordEncoder mapped for the id "null"

需要设置加密方式

4.2、设置加密方式

/**
 * 必须指定加密方式,上下加密方式要一致
 * @return
 */
@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}

登录成功,但是iframe部分页面不显示

4.3、设置允许iframe嵌套显示

默认Spring Security不允许iframe嵌套显示,我们需要设置

@Override
protected void configure(HttpSecurity http) throws Exception {
    //必须调用父类的方法,否则就不需要认证即可访问
    super.configure(http);
    //允许iframe嵌套显示
    http.headers().frameOptions().disable();
}

到目前为止,我们通过内存分配用户名密码的方式,可以访问后台页面了。

三、Spring Security集成进阶

前面我们已经完成了Spring Security的入门级配置,通过Spring Security的使用,Spring Security将我们项目中的所有资源都保护了起来,要访问这些资源必须要完成认证才能够访问。

但是这个案例中的使用方法离我们真实生产环境还差很远,还存在如下一些问题:

1、项目中我们将所有的资源(所有请求URL)都保护起来,实际环境下往往有一些资源不需要认证也可以访问,也就是可以匿名访问。

2、登录页面是由框架生成的,而我们的项目往往会使用自己的登录页面。

3、直接将用户名和密码配置在了java程序中,而真实生产环境下的用户名和密码往往保存在数据库中。

现在我们需要对这些问题进行改进。

1. 自定义登录页面

1.1 创建登录页面

① 在web-admin项目中创建templates/frame/login.html页面

DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

    <head th:include="common/head :: head">head>

    <body class="gray-bg">

        <div class="middle-box text-center loginscreen  animated fadeInDown">
            <div>
                <div>

                    <h1 class="logo-name">h1>

                div>
                <h3>欢迎使用 尚好房平台管理系统h3>

                <form class="m-t" role="form" th:action="@{/login}" method="post">
                    <label style="color:red;" th:if="${param.error}" th:text="用户名或密码错误">label>
                    <div class="form-group">
                        <input type="text" name="username" value="admin" class="form-control" placeholder="用户名" required="">
                    div>
                    <div class="form-group">
                        <input type="password" name="password" value="123456" class="form-control" placeholder="密码" required="">
                    div>
                    <button type="submit" class="btn btn-primary block full-width m-b">登 录button>


                    <p class="text-muted text-center"> <a href="javascript:"><small>忘记密码了?small>a> | <a href="javascript:">注册一个新账号a>
                    p>
                form>
            div>
        div>
    body>
html>

② 在spring-mvc.xml中配置访问登录页面的请求映射

<mvc:view-controller path="/login" view-name="frame/login"/>

1.2 修改WebSecurityConfig配置类

在WebSecurityConfig配置类中重写如下方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
    //允许iframe嵌套显示
    http.headers().frameOptions().disable();
    http
        .authorizeRequests()
        .antMatchers("/static/**","/login").permitAll()  //允许匿名用户访问的路径
        .anyRequest().authenticated()    // 其它页面全部需要验证
        .and()
        .formLogin()
        .loginPage("/login")    //用户未登录时,访问任何需要权限的资源都转跳到该路径,即登录页面,此时登陆成功后会继续跳转到第一次访问的资源页面(相当于被过滤了一下)
        .defaultSuccessUrl("/") //登录认证成功后默认转跳的路径
        .and()
        .logout()
        .logoutUrl("/logout")   //退出登陆的路径,指定spring security拦截的注销url,退出功能是security提供的
        .logoutSuccessUrl("/login");//用户退出后要被重定向的url
    //关闭跨域请求伪造
    http.csrf().disable();
}

2. 使用数据库表中的用户名和密码

2.1 注释掉内存分配用户名和密码

/*@Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("lucy")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("");
}*/

2.2 持久层

2.2.1 AdminMapper接口

service-acl项目的com.atguigu.mapper.AdminMapper接口中新增方法

Admin getByUsername(String username);
2.2.2 AdminMapper.xml映射配置文件

service-acl项目的resources/mappers/AdminMapper.xml中新增

<select id="getByUsername" resultType="Admin">
    <include refid="columns">include>
    from acl_admin
    where
    username = #{username}
    and is_deleted = 0
select>

2.3 业务层

2.3.1 AdminService接口

service-api项目的com.atguigu.service.AdminService接口中新增方法

Admin getByUsername(String username);
2.3.2 AdminServiceImpl实现类

service-acl项目的com.atguigu.service.impl.AdminServiceImpl实现类中新增方法

@Override
public Admin getByUsername(String username) {
    return adminMapper.getByUsername(username);
}

2.4 UserDetailsService接口的实现类

Spring Security支持通过实现UserDetailsService接口的方式来提供用户认证授权信息

2.4.1 新建UserDetailsServiceImpl实现类

我们在web-admin项目中创建com.atguigu.config.UserDetailsServiceImpl实现类

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Reference
    private AdminService adminService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查找用户
        Admin admin =adminService.getByUsername(username);
        if(null == admin) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
        //校验密码,操作权限目前用空的
        return new User(username,admin.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(""));
    }
}
2.4.2 添加用户时对密码进行加密

前面添加用户是我们没有对密码进行加密处理,现在改造。删除未加密的数据记录,重新创建用户信息

修改com.atguigu.controller.AdminControllersave方法

@Autowired
private PasswordEncoder passwordEncoder;
@PostMapping("/save")
public String save(Admin admin, Model model){
    //设置密码
    admin.setPassword(passwordEncoder.encode(admin.getPassword()));
    adminService.insert(admin);
    return successPage(model,"新增用户成功");
}

3. 左侧动态菜单

之前我们获取左侧动态菜单的时候,是写死用户为admin,现在可以用Spring Security获取登录的用户

修改web-admin项目中的com.atguigu.controller.IndexController类的index()方法

@GetMapping("/")
public String index(Model model){
    //获取当前登录的用户
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    User user = (User) authentication.getPrincipal();
    Admin admin = adminService.getByUsername(user.getUsername());
    //查询用户的权限列表
    List<Permission> permissionList = permissionService.findMenuPermissionByAdminId(admin.getId());
    model.addAttribute("admin",admin);
    model.addAttribute("permissionList",permissionList);
    return PAGE_INDEX;
}

4. 用户授权

4.1 获取用户权限

4.1.1 持久层
4.1.1.1 PermissionMapper接口

service-acl项目的com.atguigu.mapper.PermissionMapper接口中新增

/**
* 查询用户的操作权限
* @param adminId
* @return
*/
List<String> findCodePermissionListByAdminId(Long adminId);

/**
* 查询所有操作权限
* @return
*/
List<String> findAllCodePermission();
4.1.1.2 PermissionMapper.xml映射配置文件

service-acl项目中的resources/mappers/PermissionMapper.xml中新增

<select id="findAllCodePermission" resultType="string">
    select code from acl_permission where is_deleted=0
select>

<select id="findCodePermissionListByAdminId" resultType="string">
    SELECT code
    FROM acl_permission
    WHERE id IN (
    SELECT permission_id FROM acl_role_permission WHERE role_id IN (
    SELECT role_id FROM acl_admin_role WHERE admin_id=#{adminId} AND is_deleted=0
    ) AND is_deleted=0
    ) AND TYPE=2 AND is_deleted=0
select>
4.1.2 业务层
4.1.2.1 PermissionService接口

service-api项目的com.atguigu.service.PermissionService接口中新增

/**
* 查询用户的操作权限
* @param adminId
* @return
*/
List<String> findCodePermissionListByAdminId(Long adminId);
4.1.2.2 PermissionServiceImpl实现类

service-acl项目的com.atguigu.service.impl.PermissionServiceImpl实现类中新增

@Override
public List<String> findCodePermissionListByAdminId(Long adminId) {
    //判断是否是超级管理员
    if (adminId == 1) {
        //拥有所有权限
        return permissionMapper.findAllCodePermission();
    }
    return permissionMapper.findCodePermissionListByAdminId(adminId);
}

4.2 将用户权限配置到Spring Security中

修改web-admin项目的com.atguigu.config.UserDetailsServiceImpl

@Component
public class UserDetailServiceImpl implements UserDetailsService {
    @Reference
    private AdminService adminService;
    @Reference
    protected PermissionService permissionService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Admin admin = adminService.getByUsername(username);
        if(null == admin) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
        //获取用户权限列表
        List<String> codePermissionList = permissionService.findCodePermissionListByAdminId(admin.getId());

        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        for (String code : codePermissionList) {
            if(StringUtils.isEmpty(code)) {
                continue;
            }
            grantedAuthorityList.add(new SimpleGrantedAuthority(code));
        }
        return new User(username,admin.getPassword(), grantedAuthorityList);
    }
}

4.3 Controller方法权限控制

**目标:**给各个Controller的方法指定对应的操作权限,以角色管理增删改查等为例

4.3.1 开启Controller方法权限控制

修改web-admin项目中的com.atguigu.config.WebSecurityConfig配置类,添加下述注解

@EnableGlobalMethodSecurity(prePostEnabled = true)
4.3.2 给Controller方法添加权限注解

修改web-admin项目中的com.atguigu.controller.RoleController

@Controller
@RequestMapping("/role")
public class RoleController extends BaseController {
    @Reference
    private RoleService roleService;
    @Reference
    private PermissionService permissionService;
    private final static String LIST_ACTION = "redirect:/role";
    private static final String PAGE_ASSIGN_SHOW = "role/assignShow";

    @PreAuthorize("hasAnyAuthority('role.show')")
    @RequestMapping
    public String index(@RequestParam Map conditions, Model model){
        if(!conditions.containsKey("pageNum")) {
            conditions.put("pageNum", 1);
        }
        if(!conditions.containsKey("pageSize")) {
            conditions.put("pageSize", 10);
        }

        PageInfo<Role> pageInfo = roleService.findPage(conditions);
        model.addAttribute("page", pageInfo);
        model.addAttribute("conditions", conditions);
        return "role/index";
    }

    @PreAuthorize("hasAnyAuthority('role.create')")
    @PostMapping("/saveRole")
    public String saveRole(Role role, Model model){
        roleService.insert(role);
        return successPage(model,"添加角色成功");
    }

    @PreAuthorize("hasAnyAuthority('role.show')")
    @GetMapping("/findById/{id}")
    public String findRoleById(@PathVariable("id") Long id,Model model){
        Role role = roleService.getById(id);
        model.addAttribute("role",role);
        return "role/edit";
    }

    @PreAuthorize("hasAnyAuthority('role.edit')")
    @PostMapping("/updateRole")
    public String updateRole(Role role,Model model){
        roleService.update(role);
        return successPage(model,"更新角色成功");
    }

    @PreAuthorize("hasAnyAuthority('role.delete')")
    @GetMapping("/delete/{id}")
    public String deleteRoleById(@PathVariable("id") Long id){
        roleService.delete(id);
        return LIST_ACTION;
    }

    @PreAuthorize("hasAnyAuthority('role.assgin')")
    @GetMapping("/assignShow/{roleId}")
    public String assignShow(@PathVariable("roleId") Long roleId,Model model){
        List<Map<String, Object>> zNodes = permissionService.findPermissionByRoleId(roleId);
        model.addAttribute("zNodes", JSON.toJSONString(zNodes));
        model.addAttribute("roleId",roleId);
        return PAGE_ASSIGN_SHOW;
    }

    @PreAuthorize("hasAnyAuthority('role.assgin')")
    @PostMapping("/assignPermission")
    public String assignPermission(@RequestParam("roleId") Long roleId,
                                   @RequestParam("permissionIds") List<Long> permissionIds,
                                   Model model){
        permissionService.saveRolePermission(roleId,permissionIds);
        return successPage(model,"设置角色权限成功");
    }
}

4.4 测试

目前已admin登录,这些权限都有,点击角色管理相关功能都能正常访问。使用Admin设置某个用户只有查看角色的权限

然后admin退出登录,使用只有查看角色权限的用户登录,观察操作效果

尚好房 10_Spring Security_第3张图片

不能访问了,提示403错误状态,表示没有访问权限。

4.5 优化用户体验

上面这样提示很不友好,我们自定义提示页面

4.5.1 创建提示页面

web-admin项目中创建templates/frame/auth.html

DOCTYPE html>
<html>
    <head>
    head>
    <body style="position: relative;">
        <div style="text-align:center;margin-top: 100px;font-size: 20px;">
            <strong>没有权限strong>
        div>
    body>
html>
4.5.2 在spring-mvc.xml中配置访问提示页面

web-admin项目中的resources/spring/spring-mvc.xml中新增


<mvc:view-controller path="/auth" view-name="frame/auth"/>
4.5.3 实现AccessDeniedHandler接口

web-admin项目中创建com.atguigu.config.AtguiguAccessDeniedHandler

public class AtguiguAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        httpServletResponse.sendRedirect("/auth");
    }
}
4.5.4 在Spring Security配置类中配置AtguiguAccessDeniedHandler

修改web-admin项目中的com.atguigu.config.WebSecurityConfig

@Override
protected void configure(HttpSecurity http) throws Exception {
    //允许iframe嵌套显示
    http.headers().frameOptions().disable();
    http
        .authorizeRequests()
        .antMatchers("/static/**","/login").permitAll()  //允许匿名用户访问的路径
        .anyRequest().authenticated()    // 其它页面全部需要验证
        .and()
        .formLogin()
        .loginPage("/login")    //用户未登录时,访问任何需要权限的资源都转跳到该路径,即登录页面,此时登陆成功后会继续跳转到第一次访问的资源页面(相当于被过滤了一下)
        .defaultSuccessUrl("/") //登录认证成功后默认转跳的路径,意思时admin登录后也跳转到/user
        .and()
        .logout()
        .logoutUrl("/logout")   //退出登陆的路径,指定spring security拦截的注销url,退出功能是security提供的
        .logoutSuccessUrl("/login");//用户退出后要被重定向的url
    //关闭跨域请求伪造
    http.csrf().disable();
	
    //指定自定义的访问拒绝处理器
    http.exceptionHandling().accessDeniedHandler(new AtguiguAccessDeniedHandler());
}

4.6 优化之后的测试

尚好房 10_Spring Security_第4张图片

5. 页面功能按钮权限控制

上面我们完成了controller层方法的权限,现在我们要控制页面按钮的权限,如:角色管理上面只有查看权限,那么页面新增、修改、删除、分配权限按都不显示。

怎么实现呢?其实Spring Security已经给我们封装好了标签库,我们直接使用即可。

5.1 shf-parent工程管理依赖版本

pom.xml

<thymeleaf-springsecurity5.version>3.0.4.RELEASEthymeleaf-springsecurity5.version>

<dependency>
    <groupId>org.thymeleaf.extrasgroupId>
    <artifactId>thymeleaf-extras-springsecurity5artifactId>
    <version>${thymeleaf-springsecurity5.version}version>
dependency>

5.2 web-admin引入依赖


<dependency>
    <groupId>org.thymeleaf.extrasgroupId>
    <artifactId>thymeleaf-extras-springsecurity5artifactId>
dependency>

5.3 Thymeleaf模板引擎配置spring security 标签支持

修改web-admin项目的resources/spring/spring-mvc.xml配置文件,在Thymeleaf的模板引擎配置spring security 标签支持


<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    
    <property name="templateResolver" ref="templateResolver">property>
    
    <property name="additionalDialects">
        <set>
            <bean class="org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect" />
        set>
    property>
bean>

5.4 页面按钮控制

① 在html文件里面声明使用spring-security标签

<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

② 在相关按钮上使用标签

<button type="button" class="btn btn-sm btn-primary create" sec:authorize="hasAuthority('role.create')">新增button>

<a class="edit" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.edit')">修改a>
<a class="delete" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.delete')">删除a>
<a class="assgin" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.assgin')">分配权限a>

③ 页面完整代码

DOCTYPE html>
<html lang="en"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
      xmlns:th="http://www.thymeleaf.org">
    <head th:include="common/head :: head">head>
    <body class="gray-bg">
        <form id="ec" th:action="@{/role}" method="get">
            <div class="wrapper wrapper-content animated fadeInRight">
                <div class="row">
                    <div class="col-sm-12">
                        <div class="ibox float-e-margins">
                            <div class="ibox-content">
                                <table class="table form-table margin-bottom10">
                                    <tr>
                                        <td>
                                            <input type="text" name="roleName" th:value="${#maps.containsKey(conditions, 'roleName')} ? ${conditions.roleName} : ''" placeholder="角色名称" class="input-sm form-control"/>
                                        td>
                                    tr>
                                table>
                                <div>
                                    <button type="button" class="btn btn-sm btn-primary" onclick="javascript:document.forms.ec.pageNum.value=1;document.forms.ec.submit();">搜索button>
                                    <button type="button" onclick="addRole()"
                                            sec:authorize="hasAuthority('role.create')"
                                            class="btn btn-sm btn-primary">新增button>
                                    <button type="button" id="loading-example-btn" onclick="javascript:window.location.reload();" class="btn btn-white btn-sm">刷新button>
                                div>
                                <table class="table table-striped table-bordered table-hover dataTables-example">
                                    <thead>
                                        <tr>
                                            <th>序号th>
                                            <th>角色名称th>
                                            <th>角色编码th>
                                            <th>描述th>
                                            <th>创建时间th>
                                            <th>操作 th>
                                        tr>
                                    thead>
                                    <tbody>
                                        <tr class="gradeX" th:each="item,it : ${page.list}">
                                            <td class="text-center" th:text="${it.count}">11td>
                                            <td th:text="${item.roleName}">22td>
                                            <td th:text="${item.roleCode}">33td>
                                            <td th:text="${item.description}">33td>
                                            <td th:text="${#dates.format(item.createTime,'yyyy-MM-dd HH:mm:ss')}" >33td>
                                            <td class="text-center">
                                                <a class="edit" th:attr="data-id=${item.id}"
                                                   sec:authorize="hasAuthority('role.edit')"
                                                   onclick="editRole()" th:href="@{/role/findById/}+${item.id}">修改a>
                                                <a class="delete"
                                                   sec:authorize="hasAuthority('role.delete')"
                                                   th:attr="data-id=${item.id}" onclick="deleteRole()" th:href="@{/role/delete/}+${item.id}">删除a>
                                                <a class="assgin"
                                                   sec:authorize="hasAuthority('role.assgin')"
                                                   th:attr="data-id=${item.id}">分配权限a>
                                            td>
                                        tr>
                                    tbody>
                                table>
                                <div class="row" th:include="common/pagination :: pagination">div>
                            div>
                        div>
                    div>
                div>
            div>
        form>
        <script th:inline="javascript">
            function addRole(){
                opt.openWin("/role/create","新增",630,430)
            }

            function editRole(){
                //阻止默认
                event.preventDefault()

                opt.openWin(event.target.href,'修改',580,430);
            }

            function deleteRole(){
                //阻止默认
                event.preventDefault()

                opt.confirm(event.target.href)
            }

            $(".assgin").on("click",function () {
                var id = $(this).attr("data-id");
                opt.openWin("/role/assignShow/"+id,'修改',580,430);
            });
        script>
    body>
html>

④ 测试

如果用户没有相应的权限,那么按钮会消失

尚好房 10_Spring Security_第5张图片

你可能感兴趣的:(尚好房,spring,java,前端)