当前位置: 首页 > news >正文

Springboot整合shiro

导入依赖

   <!--    引入springboot的web项目的依赖        --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
​
<!--    shiro    --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.12.0</version></dependency>

配置类

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 {
​
​
​@Beanpublic Realm realm(){AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
​/**** @param token 这的token就是调用login方法时,传入的token对象* @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字* @throws AuthenticationException*/@Overrideprotected 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;}
​@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("============获取授权===============");
​// 从数据库表中查询当前用户具有的角色和权限字符串User user = (User) principalCollection.getPrimaryPrincipal();
​List<String> roles= getRolesFromDB(user);List<String> 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<String> getRolesFromDB(User user) {return Arrays.asList("test","admin");}
​private List<String> getPermissionFromDB(User user) {return Arrays.asList("document:read","document:write");}
​private User getUserFromDB(String username) {User user = new User(100, "数据库用户", "123456", "123@qq.com");return user;}
​@Beanpublic 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 userchainDefinition.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 {
​@Autowiredprivate ITUserService itUserService;@Autowiredprivate TUserRoleMapper tUserRoleMapper;@Autowiredprivate TRolePermsMapper tRolePermsMapper;@Autowiredprivate TPersMapper tPersMapper;@Autowiredprivate TRoleMapper tRoleMapper;
​//将Realm对象放入IOC容器里@Beanpublic Realm realm(){AuthorizingRealm authorizingRealm = new AuthorizingRealm() {
​/**** @param token 这的token就是调用login方法时,传入的token对象* @return AuthenticationInfo 对象中,封装了用户的身份信息(principals),密码(credentials),提供信息的realm的名字* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("===========获取身份信息===============");//获取身份信息String username = (String) token.getPrincipal();
​QueryWrapper<TUser> 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;}
​@Overrideprotected 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;}
​
​@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher(){
​HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();//设置算法名称matcher.setHashAlgorithmName("md5");//设置hash次数matcher.setHashIterations(1024);return matcher;
​
​}
​
​
​
​//配置Shiro过滤器链@Beanpublic 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<String> getPermissionFromDB(TUser user) {if (user.getPerms()!=null){return user.getPerms();}
​
​Integer id = user.getId();//通过用户ID找到角色
​QueryWrapper<TUserRole> wrapper1 = new QueryWrapper<>();wrapper1.eq("userid",id);TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);Integer roleid = tUserRole.getRoleid();System.out.println(roleid);
​
​QueryWrapper<TRolePerms> wrapper = new QueryWrapper<>();wrapper.select("permsid").eq("roleid",roleid);List<Object> permsidList = tRolePermsMapper.selectObjs(wrapper);System.out.println(permsidList);List<Integer> integers = permsidList.stream().map(o -> {return (Integer) o;}).collect(Collectors.toList());List<TPers> tPers = tPersMapper.selectBatchIds(integers);System.out.println(tPers);ArrayList<String> strings = new ArrayList<>();for (TPers tPer : tPers) {strings.add(tPer.getName());}user.setPerms(strings);
​return strings;}
​public List<String> getRolesFromDB(TUser user) {
​if (user.getRoleName()!=null){return user.getRoleName();}
​Integer id = user.getId();//通过用户ID找到角色QueryWrapper<TUserRole> wrapper1 = new QueryWrapper<>();wrapper1.eq("userid",id);TUserRole tUserRole = tUserRoleMapper.selectOne(wrapper1);Integer roleid = tUserRole.getRoleid();QueryWrapper<TRole> wrapper = new QueryWrapper<>();wrapper.select("name").eq("id",roleid);List<Object> roles = tRoleMapper.selectObjs(wrapper);List<String> 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.*;
​
/*** <p>* * </p>** @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<String> roleName;@TableField(exist = false)private List<String> 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<TUser> 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";
//
//    }

http://www.lryc.cn/news/158111.html

相关文章:

  • 阻塞/非阻塞、同步/异步(网络IO)
  • 为什么大家会觉得考PMP没用?
  • AVR128单片机 USART通信控制发光二极管显示
  • 为什么5G 要分离 CU 和DU?(4G分离RRU 和BBU)
  • Python中的数据输入
  • cms系统稳定性压力测试出现TPS抖动和毛刺的性能bug【杭州多测师_王sir】
  • 【UE】材质描边、外发光、轮廓线
  • 百模大战,打响AI应用生态的新赛点
  • 【C++二叉树】进阶OJ题
  • C++——vector:resize与reserve的区别,验证写入4GB大数据时相比原生操作的效率提升
  • 基础配置xml
  • win环境安装SuperMap iserver和配置许可
  • 【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(一)
  • pytest parametrize多参数接口请求及展示中文响应数据
  • 电视连续剧 ffmpeg 批量去掉片头片尾
  • 二进制搭建kubernetes
  • TDengine函数大全-系统函数
  • 北京互联网营销服务商浩希数字科技申请1350万美元纳斯达克IPO上市
  • ElementUI浅尝辄止22:Alert 警告
  • HCIP的mgre实验
  • redis cluster集群搭建
  • 小红书笔记爬虫
  • 国密GmSSL v2版本命令行方式生成国密sm2私钥、公钥、签名和验证签名
  • 2023年9月惠州/深圳CPDA数据分析师认证找弘博创新
  • it运维监控管理平台,统一运维监控管理平台
  • TDengine 官网换了新“皮肤”,来看看这个风格是不是你的菜
  • MFC:自绘CListBox,GetText返回一个乱码
  • shell 脚本发布前后端代码
  • 我的私人笔记(Linux中安装mysql)
  • IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Maven目录结构和idea的整合