• Springboot整合shiro


    导入依赖

    1.    
    2.        <dependency>
    3.            <groupId>org.springframework.bootgroupId>
    4.            <artifactId>spring-boot-starter-webartifactId>
    5.        dependency>
    6.        <dependency>
    7.            <groupId>org.apache.shirogroupId>
    8.            <artifactId>shiro-spring-boot-web-starterartifactId>
    9.            <version>1.12.0version>
    10.        dependency>

    配置类

    1. package com.qf.shiro2302.config;
    2. import com.qf.shiro2302.entity.User;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.apache.shiro.authc.AuthenticationException;
    5. import org.apache.shiro.authc.AuthenticationInfo;
    6. import org.apache.shiro.authc.AuthenticationToken;
    7. import org.apache.shiro.authc.SimpleAuthenticationInfo;
    8. import org.apache.shiro.authz.AuthorizationInfo;
    9. import org.apache.shiro.authz.SimpleAuthorizationInfo;
    10. import org.apache.shiro.realm.AuthorizingRealm;
    11. import org.apache.shiro.realm.Realm;
    12. import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
    13. import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
    14. import org.apache.shiro.subject.PrincipalCollection;
    15. import org.springframework.context.annotation.Bean;
    16. import org.springframework.context.annotation.Configuration;
    17. import java.util.Arrays;
    18. import java.util.List;
    19. @Configuration
    20. @Slf4j
    21. public class ShiroConfig {
    22.    @Bean
    23.    public Realm realm(){
    24.        AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
    25.            /**
    26.             *
    27.             * @param token 这的token就是调用login方法时,传入的token对象
    28.             * @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字
    29.             * @throws AuthenticationException
    30.             */
    31.            @Override
    32.            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    33.                System.out.println("===========获取身份信息===============");
    34.                //查询数据库获取当前用户名对应的User对象
    35.                String username = (String) token.getPrincipal();
    36.                System.out.println("username="+username);
    37.                System.out.println("this.getName()={}"+this.getName());
    38.                User user=getUserFromDB(username);
    39.                //需要返回shiro规定的AuthenticationInfo类型的对象
    40.                //这个对象中,包含了用户的身份认证信息
    41.                // SimpleAuthenticationInfo的构造函数中的第一个参数,principals代表用户的身份信息
    42.                // 一般可以使用 user对象,或者使用用户名也可以
    43.                // 第三个参数,代表当前realm的名字,固定写法
    44.                //Authentication 证明的意思
    45.                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
    46.                return authenticationInfo;
    47.           }
    48.            @Override
    49.            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    50.                System.out.println("============获取授权===============");
    51.                // 从数据库表中查询当前用户具有的角色和权限字符串
    52.                User user = (User) principalCollection.getPrimaryPrincipal();
    53.                List roles= getRolesFromDB(user);
    54.                List permissions= getPermissionFromDB(user);
    55.                // 按照约定返回AuthorizationInfo对象
    56.                SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    57.                // 放入从数据库中查询到的当前用户的角色信息
    58. //               authorizationInfo.addRole("test");
    59.                authorizationInfo.addRoles(roles);
    60.                // 放入从数据库中查询到的当前用户的权限信息
    61. //             authorizationInfo.addStringPermission("document:read");
    62.                authorizationInfo.addStringPermissions(permissions);
    63.                return authorizationInfo;
    64.           }
    65.       };
    66.        return authorizingRealm;
    67.   }
    68.    private List getRolesFromDB(User user) {
    69.        return Arrays.asList("test","admin");
    70.   }
    71.    private List getPermissionFromDB(User user) {
    72.        return Arrays.asList("document:read","document:write");
    73.   }
    74.    private User getUserFromDB(String username) {
    75.        User user = new User(100, "数据库用户", "123456", "123@qq.com");
    76.        return user;
    77.   }
    78.    @Bean
    79.    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
    80.        //ShiroFilterChainDefinition 此接口就一个实现类 默认Shiro过滤器链定义类
    81.        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
    82.        // 让登录接口直接被shiro的过滤器放行
    83.        //第一个参数:接口的路径
    84.        //第二个参数:shiro内部的过滤器的名字,anon代表无需登录即可访问的特殊的过滤器,注意过滤器的名字是固定的,不能乱写
    85.        chainDefinition.addPathDefinition("/login/dologin", "anon");
    86.        // 放行springboot的错误页面的请求url 这个页面就是个response拼接的页面
    87.        chainDefinition.addPathDefinition("/error", "anon");
    88.        //增加角色或者权限,对于某些请求
    89.        // logged in users with the 'test' role
    90. //       chainDefinition.addPathDefinition("/test/**", "authc, roles[test,admin], perms[document:read,document:write]"); 这个如果改成anon,就不能加后面的角色或者权限,否则,将会被认为需要登录,重定向到登录页
    91.        // all other paths require a logged in user
    92.        chainDefinition.addPathDefinition("/**", "authc");
    93.        return chainDefinition;
    94.   }
    95. }

    调用接口

    1. package com.qf.shiro2302.controller;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.apache.shiro.SecurityUtils;
    4. import org.apache.shiro.authc.AuthenticationToken;
    5. import org.apache.shiro.authc.UsernamePasswordToken;
    6. import org.apache.shiro.subject.Subject;
    7. import org.springframework.web.bind.annotation.PostMapping;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RestController;
    10. @RestController
    11. @RequestMapping("/login")
    12. @Slf4j
    13. public class LoginController {
    14.    @PostMapping("/dologin")
    15.    public String dologin(String username,String password){
    16.        //使用Shiro进行登录处理
    17.        Subject subject = SecurityUtils.getSubject();//获取shiro核心对象
    18.       //为了调用shiro的登录方法,需要准备一个Token对象
    19.        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
    20.        System.out.println(token);
    21.        subject.login(token);//使用shiro登录流程
    22.        return "登陆成功 ";
    23.   }
    24. }

    获取ShiroSession中的用户,注解添加权限

    1. package com.qf.shiro2302.controller;
    2. import com.qf.shiro2302.entity.User;
    3. import org.apache.shiro.SecurityUtils;
    4. import org.apache.shiro.authz.annotation.RequiresPermissions;
    5. import org.apache.shiro.authz.annotation.RequiresRoles;
    6. import org.apache.shiro.subject.Subject;
    7. import org.springframework.stereotype.Controller;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RestController;
    10. @RestController
    11. @RequestMapping("/test")
    12. public class TestController {
    13.    @RequiresRoles({"test","admin"})
    14.    @RequiresPermissions({"document:read","document:write"})
    15.    @RequestMapping("/test1")
    16.    public String hello1(){
    17.        return "hello shiro !!!";
    18.   }
    19.    @RequestMapping("/test2")
    20.    public User hello2(){
    21.        //如果使用shiro获取当前登录用户的身份信息
    22.        Subject subject = SecurityUtils.getSubject();
    23.        User principal = (User) subject.getPrincipal();
    24.        System.out.println(principal);
    25.        return principal;
    26.   }
    27. }
    1. shiro:
    2. loginUrl: /login.html
    3.  #配置没登陆的时候重定向的页面。这个请求是可以放行的

    优化整合shiro,登录密码MD5Hash加密,内置处理

    1.配置类

    1. package com.qf.shiroHomework.config;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.qf.shiroHomework.entity.*;
    4. import com.qf.shiroHomework.mapper.TPersMapper;
    5. import com.qf.shiroHomework.mapper.TRoleMapper;
    6. import com.qf.shiroHomework.mapper.TRolePermsMapper;
    7. import com.qf.shiroHomework.mapper.TUserRoleMapper;
    8. import com.qf.shiroHomework.service.ITUserService;
    9. import lombok.extern.slf4j.Slf4j;
    10. import org.apache.shiro.authc.AuthenticationException;
    11. import org.apache.shiro.authc.AuthenticationInfo;
    12. import org.apache.shiro.authc.AuthenticationToken;
    13. import org.apache.shiro.authc.SimpleAuthenticationInfo;
    14. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    15. import org.apache.shiro.authz.AuthorizationInfo;
    16. import org.apache.shiro.authz.SimpleAuthorizationInfo;
    17. import org.apache.shiro.realm.AuthorizingRealm;
    18. import org.apache.shiro.realm.Realm;
    19. import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
    20. import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
    21. import org.apache.shiro.subject.PrincipalCollection;
    22. import org.apache.shiro.util.ByteSource;
    23. import org.springframework.beans.factory.annotation.Autowired;
    24. import org.springframework.context.annotation.Bean;
    25. import org.springframework.context.annotation.Configuration;
    26. import java.util.ArrayList;
    27. import java.util.Arrays;
    28. import java.util.List;
    29. import java.util.stream.Collectors;
    30. import java.util.stream.IntStream;
    31. @Configuration
    32. @Slf4j
    33. public class ShiroConfig {
    34.    @Autowired
    35.    private ITUserService itUserService;
    36.    @Autowired
    37.    private TUserRoleMapper tUserRoleMapper;
    38.    @Autowired
    39.    private TRolePermsMapper tRolePermsMapper;
    40.    @Autowired
    41.    private TPersMapper tPersMapper;
    42.    @Autowired
    43.    private TRoleMapper tRoleMapper;
    44.    //将Realm对象放入IOC容器里
    45.    @Bean
    46.    public Realm realm(){
    47.        AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
    48.            /**
    49.             *
    50.             * @param token 这的token就是调用login方法时,传入的token对象
    51.             * @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字
    52.             * @throws AuthenticationException
    53.             */
    54.            @Override
    55.            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    56.                System.out.println("===========获取身份信息===============");
    57.                //获取身份信息
    58.                String username = (String) token.getPrincipal();
    59.                QueryWrapper wrapper = new QueryWrapper<>();
    60.                wrapper.eq("username",username);
    61.                TUser user = itUserService.getOne(wrapper);
    62.                // 需要返回shiro规定的AuthenticationInfo类型的对象
    63.                // 这个对象中,包含了用户的身份认证信息
    64.                // SimpleAuthenticationInfo的构造函数中的第一个参数,principals代表用户的身份信息
    65.                // 一般可以使用 user对象,或者使用用户名也可以
    66.                // 第三个参数: 盐
    67.                // 第四个参数,代表当前realm的名字,就是一个标识,标识是这个Bean调用的这个方法,没有作用,固定写法
    68.                SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());
    69.                return authenticationInfo;
    70.           }
    71.            @Override
    72.            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    73.                TUser user = (TUser) principalCollection.getPrimaryPrincipal();
    74.                SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
    75.                log.info("用户角色={}",getRolesFromDB(user));
    76.                log.info("用户权限={}",getPermissionFromDB(user));
    77.                authorizationInfo.addRoles(getRolesFromDB(user));
    78.                authorizationInfo.addStringPermissions(getPermissionFromDB(user));
    79.                return authorizationInfo;
    80.           }
    81.       };
    82.        // 把HashedCredentialsMatcher对象设置到authorizingRealm对象中
    83.        authorizingRealm.setCredentialsMatcher(hashedCredentialsMatcher());
    84.        return authorizingRealm;
    85.   }
    86.    @Bean
    87.    public HashedCredentialsMatcher hashedCredentialsMatcher(){
    88.        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    89.      //设置算法名称
    90.        matcher.setHashAlgorithmName("md5");
    91.        //设置hash次数
    92.        matcher.setHashIterations(1024);
    93.        return matcher;
    94.   }
    95.    //配置Shiro过滤器链
    96.    @Bean
    97.    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
    98.        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
    99.        chainDefinition.addPathDefinition("/register.html","anon");
    100.        chainDefinition.addPathDefinition("/error/500.html","anon");
    101.        chainDefinition.addPathDefinition("/error","anon");
    102.        chainDefinition.addPathDefinition("/user/register","anon");
    103.        chainDefinition.addPathDefinition("/user/login","anon");
    104.        chainDefinition.addPathDefinition("/user/**","authc");
    105.        chainDefinition.addPathDefinition("/**","authc");
    106.        return chainDefinition;
    107.   }
    108.    public List getPermissionFromDB(TUser user) {
    109.        if (user.getPerms()!=null){
    110.            return user.getPerms();
    111.       }
    112.        Integer id = user.getId();
    113.        //通过用户ID找到角色
    114.        QueryWrapper wrapper1 = new QueryWrapper<>();
    115.        wrapper1.eq("userid",id);
    116.        TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);
    117.        Integer roleid = tUserRole.getRoleid();
    118.        System.out.println(roleid);
    119.        QueryWrapper wrapper = new QueryWrapper<>();
    120.        wrapper.select("permsid").eq("roleid",roleid);
    121.        List permsidList = tRolePermsMapper.selectObjs(wrapper);
    122.        System.out.println(permsidList);
    123.        List integers = permsidList.stream().map(o -> {
    124.                    return (Integer) o;
    125.               })
    126.               .collect(Collectors.toList());
    127.        List tPers = tPersMapper.selectBatchIds(integers);
    128.        System.out.println(tPers);
    129.        ArrayList strings = new ArrayList<>();
    130.        for (TPers tPer : tPers) {
    131.            strings.add(tPer.getName());
    132.       }
    133.        user.setPerms(strings);
    134.        return strings;
    135.   }
    136.    public List getRolesFromDB(TUser user) {
    137.        if (user.getRoleName()!=null){
    138.            return user.getRoleName();
    139.       }
    140.        Integer id = user.getId();
    141.        //通过用户ID找到角色
    142.        QueryWrapper wrapper1 = new QueryWrapper<>();
    143.        wrapper1.eq("userid",id);
    144.        TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);
    145.        Integer roleid = tUserRole.getRoleid();
    146.        QueryWrapper wrapper = new QueryWrapper<>();
    147.        wrapper.select("name").eq("id",roleid);
    148.        List roles = tRoleMapper.selectObjs(wrapper);
    149.        List strings = roles.stream().map(o -> {
    150.                    return (String) o;
    151.               })
    152.               .collect(Collectors.toList());
    153.        user.setRoleName(strings);
    154.        return strings;
    155.   }
    156. }
    157. 实体类

      1. package com.qf.shiroHomework.entity;
      2. import com.baomidou.mybatisplus.annotation.IdType;
      3. import com.baomidou.mybatisplus.annotation.TableField;
      4. import com.baomidou.mybatisplus.annotation.TableId;
      5. import com.baomidou.mybatisplus.annotation.TableName;
      6. import java.io.Serializable;
      7. import java.util.List;
      8. import lombok.*;
      9. /**
      10. *

      11. *
      12. *

      13. *
      14. * @author jmj
      15. * @since 2023-08-10
      16. */
      17. @NoArgsConstructor
      18. @AllArgsConstructor
      19. @Data
      20. @TableName("t_user")
      21. public class TUser implements Serializable {
      22.    private static final long serialVersionUID = 1L;
      23.    @TableId(value = "id", type = IdType.AUTO)
      24.    private Integer id;
      25.    private String username;
      26.    private String password;
      27.    private String salt;
      28.    @TableField(exist = false) // 说明当前这个属性在数据库表中没有对应的字段,让mp生成sql时忽略这个属性
      29.    private List roleName;
      30.    @TableField(exist = false)
      31.    private List perms;
      32. }

      Controller

      1. //复杂密码匹配器
      2.    @PostMapping("/login")
      3.    public String login(TUser user){
      4.        //使用Shiro进行登录处理
      5.        Subject subject = SecurityUtils.getSubject();//获取shiro核心对象
      6.        //为了调用shiro的登录方法,需要准备一个Token对象
      7.        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());
      8.        subject.login(usernamePasswordToken);
      9.        return "redirect:/show.html";
      10.   }

      以前手写MD5处理的方法

      1. //   简单密码匹配器方案
      2. //   @PostMapping("/login")
      3. //   public String login(TUser user){
      4. //       //使用Shiro进行登录处理
      5. //       Subject subject = SecurityUtils.getSubject();//获取shiro核心对象
      6. //       //为了调用shiro的登录方法,需要准备一个Token对象
      7. //       //添加Where 条件
      8. //       QueryWrapper wrapper = new QueryWrapper<>();
      9. //       wrapper.eq("username",user.getUsername());
      10. //       TUser u = itUserService.getOne(wrapper);
      11. //       if (u==null){
      12. //           return "redirect:/index.html";
      13. //       }else {
      14. //
      15. //           //MD5加密
      16. //           Md5Hash md5Hash = new Md5Hash(user.getPassword(), u.getSalt(), 1024);
      17. //           String newPassword = md5Hash.toHex();
      18. //
      19. //
      20. //           UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), newPassword);
      21. //
      22. //           subject.login(usernamePasswordToken);
      23. //       }
      24. //
      25. //           return "redirect:/show.html";
      26. //
      27. //   }

    158. 相关阅读:
      C++智能指针之shared_ptr
      vue3 defineProps defineEmits defineExpose
      基于jenkins进行定制化开发
      Gomodule和GoPath
      JVM类加载机制
      ms17-010(永恒之蓝)漏洞复现
      PromptPort:为大模型定制的创意AI提示词工具库
      Spring Cloud Alibaba 工程搭建
      数字孪生与GIS数据为何高度互补?二者融合后能达到什么样的效果?
      求各区域热门商品Top3 - HiveSQL
    159. 原文地址:https://blog.csdn.net/qq_53374893/article/details/132649858