zoukankan      html  css  js  c++  java
  • Springboot+thymeleaf+shiro整合

    Springboot+thymeleaf+shiro

    一、简介

    1、Spring Boot

    首先,spring的诞生是Java企业版(Java Enterprise Edition,JEE或J2EE)的轻量级替代品。无需开发重量级的EJB(Enterprise JavaBean),spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入IOC和面向前面编程AOP,用简单的Java对象(POJO,Plain Old Java Object)实现了EJB的功能。

    缺陷:虽然spring的组件代码是轻量级的,但它的配置确是重量级的。

    由此,SpringBoot应运而生,SpringBoot简化了spring的应用开发,只需要*run*就能创建一个独立的,生产级别的spring应用。SpringBoot为spring平台和第三方库提供了开箱即用的设置(即:提供默认设置),只需要很少的spring配置。

    可以使用SpringBoot创建Java应用,*jar部署*方式,使用java -jar启动,也可以采用传统的war部署方式

    2、shiro

    全称为Apache Shiro,一个强大且易用的*java安全框架*,执行身份验证,授权,密码学和会话管理。使用shiro API,可以快速,轻松地获得任何应用程序。包括移动应用程序或网络和企业应用程序。

    Shiro六大体系结构

    Authentication认证 ——用户登录

    Authorization授权 ——用户具有哪些权限

    Cryptography 安全数据加密

    Session Management 会话管理

    Web Integration web系统集成

    Interations 集成其他应用,spring,缓存框架等。

    3、thymeleaf /taim.li:f/

    项目所用到的页面模板,Spring Boot之前spring应用程序通常使用的都是jsp

    Spring Boot推荐使用thymeleaf,thymeleaf在html页面的基础上添加特定标签,来实现页面模板的渲染。

    Thymeleaf是⾯向Web和独⽴环境的现代服务器端Java模板引擎,能够处 理HTML,XML,JavaScript,CSS甚⾄纯⽂本。 Thymeleaf旨在提供⼀个优雅的、⾼度可维护的创建模板的⽅式。

    为了实 现这⼀⽬标,Thymeleaf建⽴在⾃然模板的概念上,将其逻辑注⼊到模板 ⽂件中,不会影响模板设计原型。 这改善了设计的沟通,弥合了设计和 开发团队之间的差距。 Thymeleaf从设计之初就遵循Web标准——特别是HTML5标准 ,如果需 要,Thymeleaf允许您创建完全符合HTML5验证标准的模板

    二、快速入门

    1、Spring Boot快速入门

    1.1、建立maven项目,继承Spring Boot父工程

    img

    继承Spring Boot父工程

    <!-- 1、创建maven项目,继承Spring Boot父工程 -->
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.4.RELEASE</version>
    </parent>

    1.1.1、附加:Spring Boot可以方便的修改项目jdk的版本(只需要修改pom.xml的参数即可)

    原始jdk

    img

    修改pom.xml的参数

      <!-- 附加:Spring Boot可以方便的修改项目jdk的版本 -->
    <!-- 修改参数 -->
    <properties>
    <java.version>1.8</java.version>
    </properties>

    ctrl+s保存 , 右键项目--maven--Update Project

    img

    修改后的项目jdk

    img

    1.2、导入依赖——导入web支持:SpringMVC开发支持,Servlet相关程序支持等

      <!-- 2、导入依赖 -->
    <dependencies>
    <!-- 2.1、导入web支持:SpringMVC开发支持,Servlet相关程序支持等 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    </dependencies>

    1.3、编写Controller测试类:TestController(注意controller注解)

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;

    @Controller
    public class TestController {

    @RequestMapping("/hello") //访问地址映射
    @ResponseBody //相应体 ——return "success";
    public Object hello() {
    System.out.println("test------");
    return "success";
    }

    }

    1.4、编写Spring Boot启动类:Application——(@SpringBootApplication)SpringApplication.run(Application.class,args);

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication //启动类注解
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    访问形式:(即 localhost:8080/hello )

    img

     

    1.5、导入thymeleaf页面模块(引入thymeleaf依赖)

    <!-- 2.2、导入thymeleaf页面模块依赖 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    1.5.1、测试thymeleaf(在controller中添加测试方法)

        /*
    * 测试thymeleaf页面模块是否可用
    */
    @RequestMapping("/testThymeleaf")
    public String testThymeleaf(Model model) {

    //把数据存入model中
    model.addAttribute("test", "thymeleaf");

    //返回test.html     (return "test";)与return的值一致
    return "test";

    }

    1.5.2、建立前端测试页面test.html

    创建的Spring Boot是jar项目,Spring boot存放页面的地方,在src/main/resources下创建一个web页根目录(相当于webapp)——:templates,在此目录下创建test.html页面。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>测试thymeleaf页面模块是否可用</title>
    </head>
    <body>

    <!-- 一个简单的thymeleaf语法th:text="${}" -->
    <h2 th:text="${test}"></h2>
    </body>
    </html>

    问题:

    img

    img

    原因:在thymeleaf3.0以前对页面标签语法要求比较严格,开始标签必须有对应的结束标签。

    解决:1、将页面中标签语言严谨化

    img

    2、如果希望页面语法不严谨,但是也能够运行成功,可以把thymeleaf升级为3.0或以上版本。

    任何版本的更改都可以通过<properties>属性进行修改

            <!-- 2.2.1、修改thymeleaf的版本 -->
    <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
    <!-- 2.2.2、附带的版本修改 -->
    <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>

    注意:在2.2.2、附带的版本修改中,没有RELEASE

    访问:localhost:8080/testThymeleaf

     


    2、Spring boot与Shiro整合实现用户认证

    2.1、Shiro的核心API,三个核心类

    Subject:用户主体(包括用户登录,注销等方法,还有一些判断授权的方法) (关联SecurityManager,把操作交给它)

    SecurityManager:安全管理器 (关联Realm)

    Realm:Shiro连接数据库的桥梁

    2.2、导入shiro和spring的整合依赖

        <!-- 导入shiro和spring的整合依赖 -->
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
    </dependency>

    2.3、在编写Shiro配置类之前,要先自定义Realm类(用来编写查询的一些方法方式,或者是完成一些认证与授权的逻辑)

    继承 AuthorizingRealm(实现两个方法,执行授权和认证逻辑)TestRealm.java

    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    /**
    * 自定义Realm类
    * @author fzywhy
    *
    */

    public class TestRealm extends AuthorizingRealm {
    /*
    * 执行授权逻辑
    * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
    */

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
    System.out.println("执行授权逻辑");
    return null;
    }

    /*
    * 执行认证逻辑
    * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
    */

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
    System.out.println("执行认证逻辑");
    return null;
    }
    }

    2.4、编写Shiro配置类(spring中配置文件是ContextApplication.xml) ShiroConfig.java

    (创建ShiroFilterFactoryBean,创建DefaultWebSecurityManager,创建Realm(连接数据库)

    package com.fzy.shiro;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    /**
    * Shiro的配置类
    * @author fzywhy
    *
    */
    @Configuration
    public class ShiroConfig {

    /*
    * 创建ShiroFilterFactoryBean
    */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    return shiroFilterFactoryBean;
    }

    /*
    * 创建DefaultWebSecurityManager——关联realm(连接数据库)
    */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("testRealm")TestRealm testRealm) {

    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //关联realm
    securityManager.setRealm(testRealm);
    return securityManager;
    }

    /*
    * 创建Realm——自定义Realm类
    */
    @Bean //添加到spring容器中
    public TestRealm getRealm() {
    return new TestRealm();
    }

    }

    2.5、使用Shiro内置过滤器实现页面拦截(在ShiroConfig.java中)

        /*
    * 创建ShiroFilterFactoryBean
    */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {

    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    /*
    * 使用Shiro内置过滤器实现页面拦截:拦截url链接请求
    *
    * shiro内置过滤器,可以实现权限相关的拦截器
    * 常用的过滤器:
    * anon:无需认证(登录)可以访问
    * authc:必须认证才可以访问
    * user:如果使用rememberMe的功能可以直接访问 (记住用户和密码)
    * perms:该资源必须得到资源权限才可以访问 (密码验证)
    * role:该资源必须得到角色权限才可以访问 (VIP会员)
    *
    */

    //创建集合——充作拦截器集合
    Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();

    /*
    * 单个url拦截,
    */
    /*
    filterChainDefinitionMap.put("/add", "authc");
    filterChainDefinitionMap.put("/update", "authc");
    */

    //批量url拦截
    filterChainDefinitionMap.put("/*", "authc");

    //url放行
    filterChainDefinitionMap.put("/testThymeleaf", "anno");

    /*
    * shiro拦截器拦截成功后,会返回一个默认的地址login.jsp
    * 可以自定义修改调整的登录页面
    */
    shiroFilterFactoryBean.setLoginUrl("/toLogin");
    //设置拦截器map集合
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
    }

    2.5.1、在TestController.java中添加以下请求路径映射(请求全部都要经过Controller,来跳转到我们自定义的页面模板)

        //add.html用户添加
    @RequestMapping("/add")
    public String add() {
    return "/user/add";
    }

    //update.html用户更新
    @RequestMapping("/update")
    public String update() {
    return "/user/update";
    }
    //login.html自定义的登录页面
    @RequestMapping("/toLogin")
    public String login() {
    return "login";
    }

    2.5.2、页面结构

    img

    2.5.3、在test.html中

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>测试thymeleaf页面模块是否可用</title>
    </head>
    <body>

    <!-- 一个简单的thymeleaf语法th:text="${}" -->
    <h2 th:text="${test}"></h2>
    用户添加页面<a href="add">用户添加</a><br>
    用户更新页面<a href="update">用户更新</a>

    </body>
    </html>

    2.5.4、访问测试:localhost:8080/add或者是/update,都会被拦截,被转发到toLogin,而/testThymeleaf可正常访问。

    2.5.5、遇到的错误

    img

    第一个红框错误:getShiroFilterFactoryBean方法前,未加@Bean注解

    第二个红框错误:filterChainDefinitionMap.put("/testThymeleaf","ann"); 代码错误,是anon不是ann

    2.6、实现用户认证(登录)操作

    2.6.1、登录页面login.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>用户登录</title>
    </head>
    <body>

    <hr>
    <h1>用户登录</h1>
    <form method="post" action="login">
    用户名<input type="text" name="name"/><br/>
    密   码<input type="password" name="password"/><br/>
    <input type="submit" value="登录"/>
    </form>

    </body>
    </html>

    2.6.2、在Controller中编写登录逻辑(TestController.java)

        /*
    * 登录逻辑处理
    */
    @RequestMapping("/login")
    public String login(String name,String password,Model model) { //name和password也可以封装到一个user对象中,model用来返回错误信息
    /*
    * 使用Shiro编写认证操作
    * 1.获取Subject
    * 2.封装用户数据
    * 3、执行登录方法
    */
    //1.获取Subject
    Subject subject = SecurityUtils.getSubject();
    //2.封装用户数据
    UsernamePasswordToken token = new UsernamePasswordToken(name,password);
    //3.执行登录方法
    try {
    subject.login(token);
    /*
    * 无任何异常,则登录成功
    * 跳转到test.html页面
    */
    return "redirect:/testThymeleaf"; //redirect:重定向(不带数据),而非转发请求(带数据)
    } catch (UnknownAccountException e) {
    //UnKnownAccountException登录失败:用户名不存在
    model.addAttribute("msg", "用户名不存在");
    //带着msg数据,转发请求
    return "login";
    } catch (IncorrectCredentialsException e) {
    //IncorrectCredentialsException登录失败:密码错误
    model.addAttribute("msg", "密码错误");
    return "login";
    }
    }

    访问问题:localhost:8080/testThymeleaf跳转到toLogin请求中,输入用户名和密码,点击登录,此时是不成功的

    问题原因:Shiro内置拦截器将login.html的资源拦截(批量拦截)

    解决方案:在ShiroConfig.java即shiro配置类中,放行login请求

    //放行login.html页面,即放行login请求 ​ filterChainDefinitionMap.put("/login", "anon");

     

    2.6.3、在Realm中编写判断逻辑(TestRealm.java)

        /*
    * 执行认证逻辑
    * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
    */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
    System.out.println("执行认证逻辑");
    /*
    * 认证逻辑
    */
    //给定用户名和密码
    String name = "fzy";
    String password = "fzy";
    /*
    * 编写shiro的判断逻辑,判断用户名和密码
    */
    //1.判断用户名
    UsernamePasswordToken token = (UsernamePasswordToken)arg0; //将形参强制转换为TestController.java中封装的数据类型
    //如果用户名不存在
    if(!token.getUsername().equals(name)) {
    return null; //shiro底层会抛出UnknownAccountException
    }
    //2.判断密码
    return new SimpleAuthenticationInfo("", password, "");
    }

    2.7、与Mybatis整合实现登录

    2.7.1、导入mybatis的相关依赖(连接池,数据库驱动,springBoot的mybatis启动器)

        <!-- 3、导入mybatis相关依赖 -->
    <!-- 3.1、数据库导入连接池 -->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.9</version>
    </dependency>
    <!-- 3.2、导入MySQL数据库驱动 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- 3.3、导入spring boot的mybatis的启动器 -->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
    </dependency>

    2.7.2、在web资源根目录下配置application.properties(web资源根目录src/main/resources)

    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springboot
    spring.datasource.username=root
    spring.datasource.password=123456

    #连接池
    spring.datasource.type=com.alibaba.druid.pool.DruidDatasource
    #mybatis包扫描
    mybatis.type-aliases-package=com.fzy.domain

    2.7.3、编写User实体类

    package com.fzy.domain;
    /**
    * tablename=user
    * @author fzywhy
    *
    */

    public class User {
    private Integer id;
    private String name;
    private String password;
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public String getPassword() {
    return password;
    }
    public void setPassword(String password) {
    this.password = password;
    }
    }

    2.7.4、编写UserMapper接口(即dao接口)

    package com.fzy.mapper;

    import com.fzy.domain.User;

    public interface UserMapper {
    public User findUserByName(String name);
    }

    2.7.5、编写UserMapper.xml接口映射文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- 该文件存放CRUD的sql语句 -->
    <mapper namespace="com.fzy.mapper.UserMapper"> <!-- namespace:UserMapper.java的全限定类名 -->

    <!-- id:接口方法名,parameterType:参数类型,resultType:方法返回类型 -->
    <select id="findUserByName" parameterType="string" resultType="user">
    select id,name,password
    from user
    where name = #{value}
    </select>

    </mapper>

    2.7.6、编写业务接口UserService.java

    package com.fzy.service;

    import com.fzy.domain.User;
    public interface UserService {
    public User findUserByName(String name);
    }

    2.7.7、编写业务接口实现类UserServiceImpl.java(注意添加业务实现类注解@Service)

    package com.fzy.service.impl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import com.fzy.domain.User;
    import com.fzy.mapper.UserMapper;
    import com.fzy.service.UserService;

    @Service //业务实现类注解
    public class UserServiceImpl implements UserService {
    //实现类要使用mapper(即dao)接口中的方法,所以要注入mapper接口
    @Autowired
    private UserMapper usermapper;
    @Override
    public User findUserByName(String name) {
    //用mapper接口对象,调用mapper接口中的方法
    return usermapper.findUserByName(name);
    }
    }

    2.7.8、在启动类中添加mabatis扫描包注解@MapperScan("com.fzy.mapper")

    package com.fzy;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication //启动类注解
    @MapperScan("com.fzy.mapper") //添加mapper扫描包注解
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    2.7.9、改写自定义Realm类的执行认证逻辑

        //需要调用业务层service接口中的方法得到页面中的数据,注入UserService
    @Autowired
    private UserService userService;
    /*
    * 执行认证逻辑
    * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
    */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
    System.out.println("执行认证逻辑");
    // /*
    // * 认证逻辑
    // */
    // //给定用户名和密码
    // String name = "fzy";
    // String password = "fzy";
    // /*
    // * 编写shiro的判断逻辑,判断用户名和密码
    // */
    // //1.判断用户名
    // UsernamePasswordToken token = (UsernamePasswordToken)arg0; //将形参强制转换为TestController.java中封装的数据类型,即controller中传递来的数据
    // //如果用户名不存在
    // if(!token.getUsername().equals(name)) {
    // return null; //shiro底层会抛出UnknownAccountException
    // }

    // //2.判断密码 返回返回类型AuthenticationInfo的一个子类SimpleAuthenticationInfo(参数1:需要返回给login方法的数据,参数2:数据库密码,参数3:shiro名字)

    // return new SimpleAuthenticationInfo("", password, "");
    /*
    * 与mybatis整合后的认证逻辑
    */
    //判断用户名
    UsernamePasswordToken token = (UsernamePasswordToken)arg0;
    //得到用户在页面上填写的用户名
    User user = userService.findUserByName(token.getUsername());
    //如果用户名不存在
    if(user == null) {
    return null; //shiro底层抛出UnknownAccountException
    }
    //判断密码 返回返回类型AuthenticationInfo的一个子类SimpleAuthenticationInfo(参数1:需要返回给login方法的数据,参数2:数据库密码,参数3:shiro名字)
    return new SimpleAuthenticationInfo("", user.getPassword(), "");
    }

    注意:得到用户名 User user = userService.findUserByName(token.getUsername()); token.

    判断密码 return new SimpleAuthenticationInfo("",user.getPassword(),""); user.

    2.7.10、注意:建立相对应的数据库,并保存数据

    3、Spring Boot与Shiro整合实现用户授权

    3.1、使用shiro内置拦截器拦截资源ShiroConfig.java

            //授权过滤器     注意:当前授权拦截后,shiro会自动跳转到默认的未授权页面
    filterChainDefinitionMap.put("/add", "perms[user:add]"); //perms[user:add]中user:add是授权的自定义字符串
    //设置未授权的提示页面
    shiroFilterFactoryBean.setUnauthorizedUrl("noAuth");

    注意:授权过滤器需要添加到批量url资源拦截之前 (不然,程序流程走不到授权认证)

        /*
    * 创建ShiroFilterFactoryBean
    */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    /*
    * 使用Shiro内置过滤器实现页面拦截:拦截url链接请求
    *
    * shiro内置过滤器,可以实现权限相关的拦截器
    * 常用的过滤器:
    * anon:无需认证(登录)可以访问
    * authc:必须认证才可以访问
    * user:如果使用rememberMe的功能可以直接访问 (记住用户和密码)
    * perms:该资源必须得到资源权限才可以访问 (密码验证)
    * role:该资源必须得到角色权限才可以访问 (VIP会员)
    *
    */

    //创建集合——充作拦截器集合
    Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
    /*
    * 单个url拦截,
    */
    /* filterChainDefinitionMap.put("/add", "authc");
    filterChainDefinitionMap.put("/update", "authc");*/
    //url放行
    filterChainDefinitionMap.put("/testThymeleaf", "anon");
    //放行login.html页面,即放行login请求
    filterChainDefinitionMap.put("/login", "anon");

    //授权过滤器 注意:当前授权拦截后,shiro会自动跳转到默认的未授权页面
    filterChainDefinitionMap.put("/add", "perms[user:add]"); //perms[user:add]中user:add是授权的自定义字符串

    //批量url拦截
    filterChainDefinitionMap.put("/*", "authc");
    /*
    * shiro拦截器拦截成功后,会返回一个默认的地址login.jsp
    * 可以自定义修改调整的登录页面
    */
    shiroFilterFactoryBean.setLoginUrl("/toLogin");

    //设置未授权的提示页面
    shiroFilterFactoryBean.setUnauthorizedUrl("noAuth");

    //设置拦截器map集合
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;

    }

    3.1.1、在controller中添加请求url映射noAuth

        //noAuth.html——未授权提示页面
    @RequestMapping("noAuth")
    public String noAuth() {
    return "/noAuth";
    }

    3.1.2、创建noAuth.html页面

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>未授权提示页面</title>
    </head>
    <body>
    <h2>未授权,不可访问</h2>
    </body>
    </html>

    3.2、完成shiro的资源授权TestRealm.java

        /*
    * 执行授权逻辑
    * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
    */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
    System.out.println("执行授权逻辑");
    /*
    * 给资源进行授权
    */
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //添加资源的授权字符串
    info.addStringPermission("user:add"); //参数字符串与资源授权过滤器的参数值一致
    return info;
    }

    3.3、关联数据库动态授权

    3.3.1、修改数据库——添加perms字段,并保存user:add和user:updata授权字符串

    img

    3.3.2、修改User实体类

    3.3.3、添加一个mapper接口方法,根据id找到user findUserById

    3.3.4、UserMapper.xml中添加对应的sql映射

    3.3.5、在UserService业务接口中,添加对应的方法 findUserById

    3.3.6、在UserServiceImpl业务接口实现类中,添加实现新增的方法

    3.3.7、修改Realm中的授权逻辑硬编码

        /*
    * 执行授权逻辑
    * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
    */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
    System.out.println("执行授权逻辑");
    /*
    * 给资源进行授权
    */
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //添加资源的授权字符串
    // info.addStringPermission("user:add"); //参数字符串与资源授权过滤器的参数值一致
    /*
    * 改造授权字符串硬编码
    * 到数据库中查询当前登录用户的授权字符串
    */

    //获取当前用户
    Subject subject = SecurityUtils.getSubject();

    //获取执行认证返回的principal的参数
    //执行认证逻辑时判断密码返回的第一个参数user
    User user = (User)subject.getPrincipal();

    //得到user的id
    User userId = userService.findUserById(user.getId());

    //获取当前用户数据库中给定的授权字符串,并将其添加为资源的授权字符串
    info.addStringPermission(userId.getPerms());

    return info;
    }

    注意:在执行认证逻辑判断密码时,要返回一个principal的参数user

            //判断密码      返回返回类型AuthenticationInfo的一个子类SimpleAuthenticationInfo(参数1:需要返回给login方法的数据,参数2:数据库密码,参数3:shiro名字)

    return new SimpleAuthenticationInfo(user, user.getPassword(), "");

    若忘记添加,会出现以下错误

    img

    3.3.8、补充:在ShiroConfig中为update.html添加权限过滤

    filterChainDefinitionMap.put("/update", "perms[user:update]");

    4、Thymeleaf和shiro标签整合使用

    4.1、导入Thymeleaf扩展坐标

            <!-- 4、导入Thymeleaf扩展坐标 -->
    <dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
    </dependency>

    4.2、在ShiroConfig中配置ShiroDialect——在ShiroConfig类里面添加getShiroDialect方法

        /*
    * 配置ShiroDialect,用于Thymeleaf和Shiro标签配合使用
    */
    @Bean
    public ShiroDialect getShiroDialect() {
    return new ShiroDialect();
    }

    4.3、修改test.html页面中的内容(在页面上使用shiro标签)

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
    <head>
    <meta charset="UTF-8">
    <title>测试thymeleaf页面模块是否可用</title>
    </head>
    <body>
    <!-- 一个简单的thymeleaf语法th:text="${}" -->
    <h2 th:text="${test}"></h2>
    <div shiro:hasPermission="user:add">
    用户添加页面<a href="add">用户添加</a><br>
    </div>
    <div shiro:hasPermission="user:update">
    用户更新页面<a href="update">用户更新</a>
    </div>
    <a href="toLogin">登录</a>
    </body>
    </html>

    功能实现:用户只能看到自己权限允许的标签

    admin用户登录只能看到用户添加

    lhm用户登录只能看到用户更新

    请求全部都要经过Controller,来跳转到我们自定义的页面模板

    guest标签  shiro:guest  /shiro:guest  用户没有身份验证时显示相应信息,即游客访问信息。

    user标签  shiro:user    /shiro:user  用户已经身份验证/记住我登录后显示相应的信息。

    authenticated标签  shiro:authenticated    /shiro:authenticated  用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。

    notAuthenticated标签  shiro:notAuthenticated    /shiro:notAuthenticated  用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

    principal标签  <shiro: principal/>    <shiro:principal property="username"/>  相当于((User)Subject.getPrincipals()).getUsername()。

    lacksPermission标签  <shiro:lacksPermission name="org:create">  /shiro:lacksPermission  如果当前Subject没有权限将显示body体内容。

    hasRole标签  <shiro:hasRole name="admin">    /shiro:hasRole  如果当前Subject有角色将显示body体内容。

    hasAnyRoles标签  <shiro:hasAnyRoles name="admin,user">     /shiro:hasAnyRoles  如果当前Subject有任意一个角色(或的关系)将显示body体内容。

    lacksRole标签  <shiro:lacksRole name="abc">    /shiro:lacksRole  如果当前Subject没有角色将显示body体内容。 hasPermission标签  <shiro:hasPermission name="user:create">    /shiro:hasPermission  如果当前Subject有权限将显示body体内容

  • 相关阅读:
    图片采集
    资源(先备着)
    Memories of Vladimir Arnold 摘录
    Tribute to Vladimir Arnold 摘录
    Textbooks, Testing, Training: How We Discourage Thinking 笔记
    每天都有杰出数学家去世?(挖坑)
    I'm angry——人教B版选修2-3上的一个错误
    How to Study as a Mathematics Major 的笔记
    读《桑榆忆往》做的一点笔记
    《近代欧氏几何学》笔记
  • 原文地址:https://www.cnblogs.com/hello-top/p/13881451.html
Copyright © 2011-2022 走看看