springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)

项目demo链接:https://pan.baidu.com/s/1GMgDXr5Ca9kYtp6agkRi4w 提取码:j3sn

复制这段内容后打开百度网盘手机App,操作更方便哦
一,数据库设计,省略(jpa运行项目会自动创建,到第六步)
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第1张图片
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第2张图片
二,创建spring boot 项目
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第3张图片
坐标 + 项目名称
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第4张图片
下一步,在下一步

创建包,
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第5张图片
Pom.xml 添加maven依赖

Spring-boot版本改2.0.5,薪版数据连接方式不一致



    org.springframework.boot
    spring-boot-starter-data-jpa



    org.springframework.boot
    spring-boot-starter-thymeleaf




    org.springframework.boot
    spring-boot-starter-web




    org.apache.shiro
    shiro-spring
    1.4.0




    mysql
    mysql-connector-java
    runtime




    org.springframework.boot
    spring-boot-devtools
    true




    org.springframework.boot
    spring-boot-starter-test
    test

配置jpa + mysql 数据链接等等

Yml 文件添加jpa数据支持
自行修改数据库密码

spring:
  devtools:
    restart:
      enabled: false
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_shiro
    hikari: # springboot 2.0 整合了hikari ,据说这是目前性能最好的java数据库连接池
      username: root
      password: root
  jpa:
    hibernate:
      ddl-auto: update  # 第一次建表create  后面用update,要不然每次重启都会新建表
    show-sql: true      #日志中显示sql语句

# 分页配置
pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count=countSql

三、创建entity + Mapper

User类
大家自己生成set,get 方法

@Entity
public class User implements Serializable {
    @Id
    @GeneratedValue
    private Integer uid;
    @Column(unique =true)

    private String username;//帐号

    private String password; //密码;


    @ManyToMany(fetch= FetchType.EAGER)//立即从数据库中进行加载数据;
    @JoinTable(name = "UserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })
    private List roleList;// 一个用户具有多个角色


    /*  private String salt;//加密密码的盐
    private String name;//名称(昵称或者真实姓名,不同系统不同定义)
    private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.
    */
    // 省略 get set 方法
}

Role 角色类,大家自己生成set,get 方法


@Entity
public class Role {
    @Id
    @GeneratedValue
    private Integer id; // 编号

    private String description; // 角色描述,UI界面显示使用

    //角色 -- 权限关系:多对多关系;
    @ManyToMany(fetch= FetchType.EAGER)
    @JoinTable(name="RolePermission",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="permissionId")})
    private List permissions;

    // 用户 - 角色关系定义;
    @ManyToMany
    @JoinTable(name="UserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="uid")})
    private List users;// 一个角色对应多个用户


    /*private String role; // 角色标识程序中判断使用,如"admin",这个是唯一的:
    private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不会添加给用户*/
    // 省略 get set 方法
}


Permission 权限类,大家自己生成set,get 方法


@Entity
public class Permission implements Serializable {

    @Id
    @GeneratedValue
    private Integer id;//主键.

    private String name;//名称.

    private String permission; //权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view

/*    private String url;//资源路径.
    private Long parentId; //父编号
    private Boolean available = Boolean.FALSE;
    private String parentIds; //父编号列表
    @Column(columnDefinition="enum('menu','button')")
    private String resourceType;//资源类型,[menu|button]*/

    @ManyToMany
    @JoinTable(name="RolePermission",joinColumns={@JoinColumn(name="permissionId")},inverseJoinColumns={@JoinColumn(name="roleId")})
    private List roles;

    // 省略 get set 方法
}

四、Dao 层 mapper
说明:
/*
* 我们在这里直接继承 JpaRepository
* 这里面已经有很多现成的方法
* 这也是JPA的一大优点
*
* (1) CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法
(2) PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法
(3)JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法
(4)JpaSpecificationExecutor: 实现条件查询
* */
*
UserMapper

/**
 * Created by Administrator on 2018/10/2/002.
 * JpaRepository 说明:
 * User 实体类
 * Long 实体类主建的数据类型
 */

@Component
public interface UserMapper extends JpaRepository, JpaSpecificationExecutor {

    //根据id 查询用户对象
    @Query(value = "SELECT * FROM USER WHERE id = ?1", nativeQuery = true)
    User selectId(Integer id);

    //根据用户名查询用户是否存在
    @Query(value = "SELECT * FROM USER WHERE username = ?1", nativeQuery = true)
    User selectName(String username);
}

RoleMapper


@Component
public interface RoleMapper extends JpaRepository, JpaSpecificationExecutor {

    //查询所有角色
    @Query(value = "SELECT * FROM  description", nativeQuery = true)
    List selectDescription();
}

PermissionMapper


@Component
public interface PermissionMapper extends JpaRepository, JpaSpecificationExecutor {

    //查询所有的权限
    @Query(value = "SELECT permission FROM  permission", nativeQuery = true)
    List selectPermission();
}

五、Controller 控制层
LoginContoller

@Controller
public class LoginContoller {

    //====================== 首页 ==============================
    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index() {
        return "/index";
    }

    //=============== 登陆操作。post请求会自动拦截到权限shiro 认证方法 ===================
    @RequestMapping("/login")
    public String login(HttpServletRequest request, Model model) throws Exception{
        // 登录失败从request中获取shiro处理的异常信息。 shiroLoginFailure:就是shiro异常类的全类名.
        String exception = (String) request.getAttribute("shiroLoginFailure");
        System.out.println("exception=" + exception);
        String msg = "";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                model.addAttribute("mgs","账号不存在");
                System.out.println("UnknownAccountException -- > 账号不存在:");
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                model.addAttribute("mgs","密码不正确");
                System.out.println("UnknownAccountException -- > 密码不正确:");
            } else if ("kaptchaValidateFailed".equals(exception)) {
                model.addAttribute("mgs","验证码错误");
                System.out.println("UnknownAccountException -- > 验证码错误:");
            } else {
                model.addAttribute("mgs","其他异常");
            }
        }
        // 此方法不处理登录成功,由shiro进行处理,成功自动跳到上一个路径
        return "/login";
    }
}

UserController 类

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add() {
        return "user/add";
    }


    @RequestMapping(value = "/main", method = RequestMethod.GET)
    public String main() {return "user/main"; }

    @RequestMapping(value = "/update", method = RequestMethod.GET)
    public String upadte() {
        return "user/update";
    }

    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    public String delete() {
        return "user/delete";
    }

}

六、编写页面
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第6张图片
Login 页面


记住我

Index页面


  

hello,登陆成功

用户管理

权限加载到数据库
查看列表
添加
修改 删除 退出系统

Error 页面


   

没有权限

User下的增删改查页
自己修改了


   

查看数据

添加数据

删除数据

修改数据

先试一下项目正常不了,运行项目会自己创建数据库
springboot + jpa 配置完成了

下面开始配置shiro,

七、创建 ShiroConfig 配置文件
hashedCredentialsMatcher 密码凭证先住掉,配置了密码加密加盐在使用,
不然看不懂无法登陆系统,因为登陆密码加密
同时把myShiroRealm(hashedCredentialsMatcher()) 里面的对象去掉 myShiroRealm()

http://localhost:8080/index
会被sliro拦截到并跳转到 login 页面,并保存该路径
登录错误会执行login方法
登录成功跳转到之前输入的url地址方法

import com.example.springbootshiro.ShiroRealm.MyShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {


    /*======================== 安全管理器 ===================================  */
     @Bean
     public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        //使用了密码凭证使用,并注调上一行
       // securityManager.setRealm(myShiroRealm(hashedCredentialsMatcher()));
        return securityManager;
    }
    /*======================== 密码凭证器 ===================================  */
  /*  @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512等。
        hashedCredentialsMatcher.setHashIterations(1);//散列的次数,默认1次, 设置两次相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }*/


    /*=================== 自定义 realm=====================*/
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }
    //使用了密码凭证使用下列方法
 /*   @Bean
    public MyShiroRealm myShiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return myShiroRealm;
    }*/

    /*================= Filter工厂,设置对应的过滤条件和跳转条件 =========================  */
    //
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map map = new HashMap();
        //登出
        map.put("/logout", "logout");
        //对所有用户认证
        map.put("/**", "authc");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /*================= 加入注解的使用,不加入这个注解不生效 =========================  */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

八、创建Realm(认证与授权) MyShiroRealm类

/*
*  shiro 认证、授权类
* */
public class MyShiroRealm extends AuthorizingRealm {

    /**
     * 注意此处需要添加@Lazy注解,否则SysUserService缓存注解、事务注解不生效
     */
    @Autowired
    @Lazy
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    //============================ 授权 =======================================
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取SimpleAuthorizationInfo 对象信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取户信息
        User user  = (User)principals.getPrimaryPrincipal();
       if(user.getUsername().equals("admin")){
           //所有权限
           info.addStringPermission("*:*");
       }else {
           //获取用户角色
           for(Role role : user.getRoleList()){
               //把角色加入到 authorizationInfo 对象中
               info.addRole(role.getDescription());
               //获取角色权限
               for(Permission permission : role.getPermissions()){
                   //把权限加入到 authorizationInfo 对象中
                   info.addStringPermission(permission.getPermission());
               }
           }
       }
        return info;
    }

       /*当然也可以添加set集合:roles是从数据库查询的当前用户的角色,stringPermissions是从数据库查询的当前用户对应的权限
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(stringPermissions);*/
      //静态授权 list集合,分支判断是某某用户登录,添加该用户权限到list集合,info.addStringPermission(list)


    //============================ 认证方法 =======================================
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)//authenticationToken
            throws AuthenticationException {
        //获取用户信息
        String username = (String)token.getPrincipal();
        //获取数据库信息
        User user  = (User) userMapper.selectName(username);
        //数据空返回空,无任何权限
        if(user == null){return null; }

        //密码判断,shiro处理(用户对象 ,密码,加盐(用户名,),自定义的Realm的名称),
        // 注:可不加盐,需于登陆,注册账号配置一致,无密码凭证去掉第3个属性
 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),  getName()) ;
        /*SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getUsername()), getName()) ;*/
        return info;
    }
    /*
     *  1, 获取token中用户的输入的账号 --> username
     *  2, 通过username从数据库中查找 User对象
     *  3, User对象不存在,验证失败返回空
     *  4, 创建SimpleAuthenticationInfo,把用户对象 ,密码,自定义的Realm的名称放入进行秘密认证
     *  5、登录认证成功自动跳转到输入的 url,失败到login方法
     *  实际项目中,User对象可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
     * */
}

把认证方法内容注掉返回空,看看是不是登陆链接是不是进不去了,呵呵
认证方法逻辑根据需求更改
打开认证,会自己匹配数据库密码,不匹配返回到 login 方法,返回错误信息
匹配成功自动跳到输入的url 链接

springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第7张图片
启动项目输入 localhost:8080/index 进入login 拦截到登陆页 保存index 路径
此时数据库无数据,会拦截到logn 页面
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第8张图片
点击登陆会拦截到login 方法,提示账号密码错误信息
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第9张图片数据库添加数据登陆认证
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第10张图片
登陆会执行reaim 认证方法,根据用户名(dao层自己写的sql) 查询数据库是否存在改用户,不存在返回 null,跳到 login方法拦截异常返回前台相关错误信息,无账号此时后台会报出UnknownAccountException 异常
,存在继续下走,判断密码是否正常,shiro 后台处理,数据库密码加了盐,需要添加第3属性,密码错误后台会报出IncorrectCredentialsException 异常
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第11张图片
此时输入数据库的账号密码 登陆成功。

九、对方法添加权限控制(授权)
创建 PermissionName 注解支持 接口类

/*
*  shior保存权限的名称的注解支持类
* */

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionName {
    String value();
}

Usercontroller 改为

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    @RequiresPermissions("user:add")
    @PermissionName("用户添加")
    public String add() {
        return "user/add";
    }


    @RequestMapping(value = "/main", method = RequestMethod.GET)
    @RequiresPermissions("user:main")
    @PermissionName("用户查看")
    public String main() {return "user/main"; }

    @RequestMapping(value = "/update", method = RequestMethod.GET)
    @RequiresPermissions("user:update")
    @PermissionName("用户修改")
    public String upadte() {
        return "user/update";
    }

    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    @PermissionName("用户删除")
    @RequiresPermissions("user:delete")
    public String delete() {
        return "user/delete";
    }
}

十、一键生成所有权限到数据库
根据springMvc的方法获取权限名称
根据自定义的权限名称name 同步保存
可以根据业务自行生成

PermissionController 

/*
 *  权限加载类
 * */
@Controller
@RequestMapping("/permission")
public class PermissionController {

    @Autowired
    private PermissionMapper permissionMapper;

    //springMvc请求映射处理器
    @Autowired
    RequestMappingHandlerMapping pmhm = new RequestMappingHandlerMapping();

    @RequestMapping("/reload")
    public String reload() {
        //查询所有权限
        final List permissionList = permissionMapper.selectPermission();
        //获取所有controller中有映射标签 @RequestMapping 的方法
        Map handlerMethods = pmhm.getHandlerMethods();
        Collection methods = handlerMethods.values();
        //遍历标签找到有权限标签 @RequiresPermissions 的方法
        for (HandlerMethod method : methods) {
            RequiresPermissions methodAnnotation = method.getMethodAnnotation(RequiresPermissions.class);
            if (methodAnnotation != null) {
                //获得具体权限,封装到permission对象
                String permissionValue = methodAnnotation.value()[0];
                //如果所有权限中包含了该权限,跳出本次循环
                if(permissionList.contains(permissionValue)){
                    continue;
                }
                //权限添加数据库
                Permission permission = new Permission();
                permission.setPermission(permissionValue);                                     //权限
                permission.setName(method.getMethodAnnotation(PermissionName.class).value());  //权限名称
                permissionMapper.save(permission);
            }
        }
        return "/index";
    }
}

前台url 加载权限按钮 链接生成,走的dao 层自定义sql 语句
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第12张图片
数据库自动生成了相关权限
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第13张图片
现在这里的方法都有了权限控制
User 的方法现在都不能访问了,会跳到配置的错误页 error

在数据库-设置权限
下面是我的表数据

权限表
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第14张图片
用户表
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第15张图片
角色表
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第16张图片
用户角色中间表(管理员又1.修改 2 删除. 3添加 4,查看的权限,不需要设置)
设置张三 开发+测试
李四 测试
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第17张图片
角色与权限中间表,
测试只有查看权限,开发有增删改查权限
Zhangsan是开发+测试 = 有了增删改查 权限
Lisi 是测试 = 只有查看 权限
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第18张图片
开始测试,先退出系统,或重启服务器
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第19张图片
使用zhangsan 登陆,可以访问增删改查方法,每点击一次访问,都会进入授权方法

然后我们在退出系统
使用 lisi 登陆,发现除了查看,增删改都没权限了,并跳到error 提示页

如果出了问题自行检查授权方法是否存在逻辑问题,dobug
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第20张图片
到这里,权限配置就完成了

十一、密码加密加盐方法MD5_Shiro类

建立工具类 MD5_Shiro

public class MD5_Shiro {
    /**
     * 随机生成 salt 需要指定 它的字符串的长度
     *
     * @param len 字符串的长度
     * @return salt
     */
    public static String generateSalt(int len) {
        //一个Byte占两个字节
        int byteLen = len >> 1;
        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
        return secureRandom.nextBytes(byteLen).toHex();
    }

    /**
     * 获取加密后的密码,使用默认hash迭代的次数 1 次
     *
     * @param hashAlgorithm hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
     * @param password      需要加密的密码
     * @param salt          盐
     * @return 加密后的密码
     */
    public static String encryptPassword(String hashAlgorithm, String password, String salt) {
        return encryptPassword(hashAlgorithm, password, salt, 1);
    }

    /**
     * 获取加密后的密码,需要指定 hash迭代的次数
     *
     * @param hashAlgorithm  hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
     * @param password       需要加密的密码
     * @param salt           盐
     * @param hashIterations hash迭代的次数
     * @return 加密后的密码
     */
    public static String encryptPassword(String hashAlgorithm, String password, String salt, int hashIterations) {
        SimpleHash hash = new SimpleHash(hashAlgorithm, password, salt, hashIterations);
        return hash.toString();
    }

测试类test,生成 zhangsan 用户密文保存手动复制保存到数据库
这里的加盐规则是MD5 密码+用户名,MD5重复加密1次,
MD5(MD5(密码+用户名)),用户名就是盐,可以自定义

@Test
public void contextLoads() {
    String str = MD5_Shiro.encryptPassword("MD5","123456","zhangsan",1);
    System.out.println(str);
}

获取密文手动复制保存到数据库
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第21张图片
复制到数据库
springboot -- 整合 shiro 认证+授权+密码加盐+加载权限(jpa)_第22张图片
此时张三都无法登陆系统了,提示密码错误
我们要修改ShiroConfig 类打开密码凭证
ShiroConfig 配置类修改为

@Configuration
public class ShiroConfig {


    /*======================== 安全管理器 ===================================  */
     @Bean
     public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //securityManager.setRealm(myShiroRealm());
        //使用了密码凭证使用,并注调上一行
        securityManager.setRealm(myShiroRealm(hashedCredentialsMatcher()));
        return securityManager;
    }
    /*======================== 密码凭证器 ===================================  */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512等。
        hashedCredentialsMatcher.setHashIterations(1);//散列的次数,默认1次, 设置两次相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }


    /*=================== 自定义 realm=====================*/
 /*   @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }*/
    //使用了密码凭证使用下列方法
    @Bean
    public MyShiroRealm myShiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return myShiroRealm;
    }

    /*================= Filter工厂,设置对应的过滤条件和跳转条件 =========================  */
    //
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map map = new HashMap();
        //登出
        map.put("/logout", "logout");
        //对所有用户认证
        map.put("/**", "authc");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /*================= 加入注解的使用,不加入这个注解不生效 =========================  */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

认证方法 Realm 的认证方法加密加盐
密码凭证器 和 认证方法的加盐次数,加密方式等需一致

MyShiroRealm类
在这里插入图片描述
改为
在这里插入图片描述

此时admin 和lisi 用户登陆密码不正确,因为数据库密码没加密
而 zhangsan 可以登陆,
注意,加密规则配置config 的密码凭证 必须与 MD5_Shiro.encryptPassword的一致

Ok,shiro 配置就完成了,缓存和记住我大家可以自己研究研究,
谢谢观看----

你可能感兴趣的:(springboot)