Springboot整合shiro

导入依赖

   
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.apache.shiro
            shiro-spring-boot-web-starter
            1.12.0
        

配置类

package com.qf.shiro2302.config;
​
import com.qf.shiro2302.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
​
import java.util.Arrays;
import java.util.List;
​
@Configuration
@Slf4j
public class ShiroConfig {
​
​
​
    @Bean
    public Realm realm(){
        AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
​
            /**
             *
             * @param token 这的token就是调用login方法时,传入的token对象
             * @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字
             * @throws AuthenticationException
             */
            @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
                System.out.println("===========获取身份信息===============");
                //查询数据库获取当前用户名对应的User对象
                String username = (String) token.getPrincipal();
                System.out.println("username="+username);
                System.out.println("this.getName()={}"+this.getName());
                User user=getUserFromDB(username);
​
                //需要返回shiro规定的AuthenticationInfo类型的对象
                //这个对象中,包含了用户的身份认证信息
                // SimpleAuthenticationInfo的构造函数中的第一个参数,principals代表用户的身份信息
                // 一般可以使用 user对象,或者使用用户名也可以
                // 第三个参数,代表当前realm的名字,固定写法
                //Authentication 证明的意思
                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
​
                return authenticationInfo;
            }
​
            @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                System.out.println("============获取授权===============");
​
                // 从数据库表中查询当前用户具有的角色和权限字符串
                User user = (User) principalCollection.getPrimaryPrincipal();
​
                List roles= getRolesFromDB(user);
                List permissions= getPermissionFromDB(user);
​
                // 按照约定返回AuthorizationInfo对象
                SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
                // 放入从数据库中查询到的当前用户的角色信息
//                authorizationInfo.addRole("test");
                authorizationInfo.addRoles(roles);
​
                // 放入从数据库中查询到的当前用户的权限信息
//             authorizationInfo.addStringPermission("document:read");
                authorizationInfo.addStringPermissions(permissions);
                return authorizationInfo;
            }
        };
​
​
        return authorizingRealm;
​
​
    }
​
    private List getRolesFromDB(User user) {
        return Arrays.asList("test","admin");
    }
​
    private List getPermissionFromDB(User user) {
        return Arrays.asList("document:read","document:write");
    }
​
    private User getUserFromDB(String username) {
        User user = new User(100, "数据库用户", "123456", "[email protected]");
        return user;
    }
​
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        //ShiroFilterChainDefinition 此接口就一个实现类  默认Shiro过滤器链定义类
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
​
        // 让登录接口直接被shiro的过滤器放行
        //第一个参数:接口的路径
        //第二个参数:shiro内部的过滤器的名字,anon代表无需登录即可访问的特殊的过滤器,注意过滤器的名字是固定的,不能乱写
        chainDefinition.addPathDefinition("/login/dologin", "anon");
        // 放行springboot的错误页面的请求url  这个页面就是个response拼接的页面
        chainDefinition.addPathDefinition("/error", "anon");
​
​
        //增加角色或者权限,对于某些请求
        // logged in users with the 'test' role
//        chainDefinition.addPathDefinition("/test/**", "authc, roles[test,admin], perms[document:read,document:write]");  这个如果改成anon,就不能加后面的角色或者权限,否则,将会被认为需要登录,重定向到登录页
​
        // all other paths require a logged in user
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }
}

调用接口

package com.qf.shiro2302.controller;
​
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
@RestController
@RequestMapping("/login")
@Slf4j
public class LoginController {
​
    @PostMapping("/dologin")
    public String dologin(String username,String password){
​
        //使用Shiro进行登录处理
        Subject subject = SecurityUtils.getSubject();//获取shiro核心对象
       //为了调用shiro的登录方法,需要准备一个Token对象
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        System.out.println(token);
        subject.login(token);//使用shiro登录流程
​
        return "登陆成功 ";
​
​
    }
​
}

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

package com.qf.shiro2302.controller;
​
import com.qf.shiro2302.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
@RestController
@RequestMapping("/test")
public class TestController {
​
​
    @RequiresRoles({"test","admin"})
    @RequiresPermissions({"document:read","document:write"})
    @RequestMapping("/test1")
    public String hello1(){
        return "hello shiro !!!";
    }
​
​
    @RequestMapping("/test2")
    public User hello2(){
        //如果使用shiro获取当前登录用户的身份信息
        Subject subject = SecurityUtils.getSubject();
        User principal = (User) subject.getPrincipal();
        System.out.println(principal);
        return principal;
    }
}
shiro:
  loginUrl: /login.html
  #配置没登陆的时候重定向的页面。这个请求是可以放行的

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

1.配置类

package com.qf.shiroHomework.config;
​
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.shiroHomework.entity.*;
import com.qf.shiroHomework.mapper.TPersMapper;
import com.qf.shiroHomework.mapper.TRoleMapper;
import com.qf.shiroHomework.mapper.TRolePermsMapper;
import com.qf.shiroHomework.mapper.TUserRoleMapper;
import com.qf.shiroHomework.service.ITUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
​
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
​
@Configuration
@Slf4j
public class ShiroConfig {
​
    @Autowired
    private ITUserService itUserService;
    @Autowired
    private TUserRoleMapper tUserRoleMapper;
    @Autowired
    private TRolePermsMapper tRolePermsMapper;
    @Autowired
    private TPersMapper tPersMapper;
    @Autowired
    private TRoleMapper tRoleMapper;
​
    //将Realm对象放入IOC容器里
    @Bean
    public Realm realm(){
        AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
​
            /**
             *
             * @param token 这的token就是调用login方法时,传入的token对象
             * @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字
             * @throws AuthenticationException
             */
            @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
                System.out.println("===========获取身份信息===============");
                //获取身份信息
                String username = (String) token.getPrincipal();
​
                QueryWrapper wrapper = new QueryWrapper<>();
                wrapper.eq("username",username);
                TUser user = itUserService.getOne(wrapper);
​
                // 需要返回shiro规定的AuthenticationInfo类型的对象
                // 这个对象中,包含了用户的身份认证信息
                // SimpleAuthenticationInfo的构造函数中的第一个参数,principals代表用户的身份信息
                // 一般可以使用 user对象,或者使用用户名也可以
                // 第三个参数: 盐
                // 第四个参数,代表当前realm的名字,就是一个标识,标识是这个Bean调用的这个方法,没有作用,固定写法
​
                SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());
​
                return authenticationInfo;
            }
​
            @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                TUser user = (TUser) principalCollection.getPrimaryPrincipal();
                SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
                log.info("用户角色={}",getRolesFromDB(user));
                log.info("用户权限={}",getPermissionFromDB(user));
                authorizationInfo.addRoles(getRolesFromDB(user));
                authorizationInfo.addStringPermissions(getPermissionFromDB(user));
                return authorizationInfo;
            }
        };
​
        // 把HashedCredentialsMatcher对象设置到authorizingRealm对象中
        authorizingRealm.setCredentialsMatcher(hashedCredentialsMatcher());
​
        return authorizingRealm;
    }
​
​
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
​
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
      //设置算法名称
        matcher.setHashAlgorithmName("md5");
        //设置hash次数
        matcher.setHashIterations(1024);
        return matcher;
​
​
    }
​
​
​
​
    //配置Shiro过滤器链
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        chainDefinition.addPathDefinition("/register.html","anon");
        chainDefinition.addPathDefinition("/error/500.html","anon");
        chainDefinition.addPathDefinition("/error","anon");
        chainDefinition.addPathDefinition("/user/register","anon");
        chainDefinition.addPathDefinition("/user/login","anon");
        chainDefinition.addPathDefinition("/user/**","authc");
        chainDefinition.addPathDefinition("/**","authc");
​
​
        return chainDefinition;
​
    }
​
    public List getPermissionFromDB(TUser user) {
        if (user.getPerms()!=null){
            return user.getPerms();
        }
​
​
        Integer id = user.getId();
        //通过用户ID找到角色
​
        QueryWrapper wrapper1 = new QueryWrapper<>();
        wrapper1.eq("userid",id);
        TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);
        Integer roleid = tUserRole.getRoleid();
        System.out.println(roleid);
​
​
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.select("permsid").eq("roleid",roleid);
        List permsidList = tRolePermsMapper.selectObjs(wrapper);
        System.out.println(permsidList);
        List integers = permsidList.stream().map(o -> {
                    return (Integer) o;
                })
                .collect(Collectors.toList());
        List tPers = tPersMapper.selectBatchIds(integers);
        System.out.println(tPers);
        ArrayList strings = new ArrayList<>();
        for (TPers tPer : tPers) {
            strings.add(tPer.getName());
        }
        user.setPerms(strings);
​
        return strings;
    }
​
    public List getRolesFromDB(TUser user) {
​
        if (user.getRoleName()!=null){
            return user.getRoleName();
        }
​
        Integer id = user.getId();
        //通过用户ID找到角色
        QueryWrapper wrapper1 = new QueryWrapper<>();
        wrapper1.eq("userid",id);
        TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);
        Integer roleid = tUserRole.getRoleid();
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.select("name").eq("id",roleid);
        List roles = tRoleMapper.selectObjs(wrapper);
        List strings = roles.stream().map(o -> {
                    return (String) o;
                })
                .collect(Collectors.toList());
        user.setRoleName(strings);
        return strings;
    }
​
} 
  

实体类

package com.qf.shiroHomework.entity;
​
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.List;
​
import lombok.*;
​
/**
 * 

* *

* * @author jmj * @since 2023-08-10 */ @NoArgsConstructor @AllArgsConstructor @Data @TableName("t_user") public class TUser implements Serializable { ​    private static final long serialVersionUID = 1L; ​    @TableId(value = "id", type = IdType.AUTO)    private Integer id; ​    private String username; ​    private String password; ​    private String salt; ​    @TableField(exist = false) // 说明当前这个属性在数据库表中没有对应的字段,让mp生成sql时忽略这个属性    private List roleName;    @TableField(exist = false)    private List perms; ​ ​ ​ ​ }

Controller

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

以前手写MD5处理的方法

//    简单密码匹配器方案
//    @PostMapping("/login")
//    public String login(TUser user){
//        //使用Shiro进行登录处理
//        Subject subject = SecurityUtils.getSubject();//获取shiro核心对象
//        //为了调用shiro的登录方法,需要准备一个Token对象
//        //添加Where 条件
//        QueryWrapper wrapper = new QueryWrapper<>();
//        wrapper.eq("username",user.getUsername());
//        TUser u = itUserService.getOne(wrapper);
//        if (u==null){
//            return "redirect:/index.html";
//        }else {
//
//            //MD5加密
//            Md5Hash md5Hash = new Md5Hash(user.getPassword(), u.getSalt(), 1024);
//            String newPassword = md5Hash.toHex();
//
//
//            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), newPassword);
//
//            subject.login(usernamePasswordToken);
//        }
//
//            return "redirect:/show.html";
//
//    }

你可能感兴趣的:(SpringBoot,spring,boot,后端,java)