SpringBoot与Shiro整合-权限管理实战视频笔记(之二)

本文内容大部分来自黑马视频的SpringBoot与Shiro整合-权限管理实战视频,在此记录为个人学习笔记。
可按步骤操作,无法实操的实战blog都是耍流氓。

三、shiro认证-ShiroConfig配置类

1. shiro的核心API
  • Subject:用户主体(关联SecurityManager,把操作交给SecurityManager)
  • SecurityManager:安全管理器(关联Realm)
  • Realm:shiro连接数据库的桥梁
2. Spring整合shiro

(1)导入shiro和spring整合依赖

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

(2)自定义Realm类

package com.fukaiit.shiro;

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;

public class UserRealm extends AuthorizingRealm{

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

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

}

(3)编写shiro配置类(基本结构)

package com.fukaiit.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 Administrator
 *
 */
@Configuration
public class ShiroConfig {
    /**
     * 创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
//      设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getdefaultDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //关联Realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建Realm
     */

    @Bean(name="userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

四、shiro认证-使用shiro过滤器实现认证资源拦截

1. 在templates下新建user/add.html和user/update.html这里写图片描述
2. 在UserController中编写访问这两个页面的方法
@RequestMapping("/add")
    public String add() {
        return "user/add";
    }

    @RequestMapping("/update")
    public String update() {
        return "user/update";
    }
3. 在testThymeleaf.html页面中添加这两个页面的超链接
进入用户新增页面:<a href="add">用户新增</a>
进入用户更新页面:<a href="update">用户更新</a>

测试可访问。

4. 在getShiroFilterFactoryBean方法中添加拦截
@Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //添加shiro内置过滤器,实现权限相关的url拦截
        /**
         * 常见过滤器:
         * anon:无需认证(登录)可以访问
         * authc:必须认证才可以访问
         * user:如果使用Remember Me的功能,可以直接访问
         * perms:该资源必须得到资源权限才可以访问
         * role:该资源必须得到角色权限才可以访问
         */
        Map<String, String> filterMap=new LinkedHashMap<String, String>();
        filterMap.put("/add", "authc");
        filterMap.put("/update", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

拦截之后重启,再次访问发现:试图访问add或者update,会自动跳转到login.jsp页面

5. 修改拦截后跳转的页面

(1)在templates下新增login.html页面
(2)在ShiroConfig中shiroFilterFactoryBean方法中修改拦截后跳转的页面

//修改跳转的登录页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

(3)在UserController中添加toLogin方法

@RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }

测试,当没有权限跳转到该login.html页面

6. 试试用通配符拦截
filterMap.put("/testThymeleaf", "anon");
        filterMap.put("/*", "authc");

五、shiro认证-实现用户登录功能

1. 修改完善之前的login.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
    <h1>登录页面</h1>   
    <span style="color:red" th:text="${msg}"></span>
    <form method="post" action="login">
        <input type="text" name="username" /><br>
        <input type="password" name="password"><br>
        <input type="submit" name="submit" value="登录">
    </form> 
</body>
</html>
2. 在UserController中编写/login请求,编写登录的处理逻辑
@RequestMapping("/login")
    public String login(String usernam,String password,Model model) {
        /**
         * 使用shiro编写认证操作
         */
        //获取Subject
        Subject subject=SecurityUtils.getSubject();
        //封装用户数据
        UsernamePasswordToken token=new UsernamePasswordToken(usernam,password);
        //执行登录方法
        try {
            //只要执行login方法,就会去执行UserRealm中的认证逻辑
            subject.login(token);

            //如果没有异常,代表登录成功
            //跳转到textThymeleaf页面,代表主页
            return "redirect:/testThymeleaf";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            //登录失败
            model.addAttribute("msg","用户名不存在");
            return "login";

        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

测试发现,并没有进入/login请求,是因为之前写的拦截器(/*)拦截了所有请求,再对/login请求放行filterMap.put("/login", "anon");
重启测试,发现执行了认证逻辑,返回了用户名不存在异常。

3. 在UserRealm中编写shiro认证逻辑
@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        System.out.println("执行认证逻辑");

        //先写模拟数据进行验证,下一步再连接数据库,假设数据库的用户名和密码如下
        String dbusername="fukaiit";
        String dbpassword="123456";

        //编写shiro判断逻辑,判断用户名和密码

        //1. 判断用户名
        UsernamePasswordToken token=(UsernamePasswordToken) arg0;
        if (!token.getUsername().equals(dbusername)) {
            //用户名不存在
            return null;//shiro底层会抛出UnknownAccountException
        }
        //2. 判断密码
        return new SimpleAuthenticationInfo("",dbpassword,"");//参数1:需要返回给login方法的数据;参数2:数据库密码,shiro会自动判断 

    }
4. 启动程序,进行测试

这里写图片描述

六、shiro认证-整合MyBatis完善用户登录

1. 导入Mybatis相关的依赖
<!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- Spring的MyBatis启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
2. 配置application.properties(src/main/resources下)

(1)创建用户表

-- 创建用户表
CREATE TABLE USER(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20),
  PASSWORD VARCHAR(20)
);

(2)配置application.properties

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

# 连接池配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# mybatis 别名扫描
mybatis.type-aliases-package=com.fukaiit.domain
3. 编写User实体类
package com.fukaiit.domain;

public class User {
    private Integer id;
    private String username;
    private String password;

    //getter and setter methods
}
4. 编写接口UserMapper.java(dao)
package com.fukaiit.mapper;

import com.fukaiit.domain.User;

public interface UserMapper {
    public User findByUsername(String username);
}
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">
<mapper namespace="com.fukaiit.mapper.UserMapper">
  <select id="findByUsername" parameterType="String" resultType="User" >
    select id,username,password from user where username = #{value}
  </select>
</mapper>

Tips:
1. xml的名字必须与接口文件的名字一致;
2. mapper中的namespace必须与接口类的全名一致

6. 编写UserService.java业务接口
package com.fukaiit.service;

import com.fukaiit.domain.User;

public interface UserService {
    public User findByUsername(String username);
}
7. 编写UserServiceImpl.java业务实现类
package com.fukaiit.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fukaiit.domain.User;
import com.fukaiit.mapper.UserMapper;
import com.fukaiit.service.UserService;

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public User findByUsername(String username) {
        return userMapper.findByUsername(username);
    }

}
8. 在启动类添加@MapperScan注解,开启Mybatis的Mapper接口扫描
@MapperScan("com.fukaiit.mapper")
9. 修改UserRealm.java,调用刚编写的业务
@Autowired
    private UserService userService;

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

        //编写shiro判断逻辑,判断用户名和密码
        //1. 判断用户名
        UsernamePasswordToken token=(UsernamePasswordToken) arg0;
        User user = userService.findByUsername(token.getUsername());
        if (user==null) {
            //用户名不存在
            return null;//shiro底层会抛出UnknownAccountException
        }
        //2. 判断密码
        return new SimpleAuthenticationInfo("",user.getPassword(),"");//参数1:需要返回给login方法的数据;参数2:数据库密码,shiro会自动判断 

    }
10. run

效果同上节最后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值