Springboot整合Shiro

Springboot整合Shiro

一、登录认证

1、搭建环境

下一步:

下一步:

下一步:

完成springboot项目构建

2、pom.xml导入依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
          
        </dependency>
<!-- shiro核心依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.9.0</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <!--mysqL-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- log4j日志依赖 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

3、application.properties配置文件添加内容

#配置项目端口号
server.port=8080

#数据库
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot_shiro?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#mybatis-plus
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

shiro.loginUrl= /myController/userLogin

4、创建数据库以及表

#建库
create database  springboot_shiro character set utf8mb4;
#建表
CREATE TABLE `user` (
  `id` int(255) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(1000) DEFAULT NULL COMMENT '姓名',
  `pwd` varchar(1000) DEFAULT NULL COMMENT '密码',
  `rid` int(255) DEFAULT NULL COMMENT '角色id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

5、添加实体类user

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private  Integer id;
    private String name;
    private String pwd;
    private String rid;
}

6、添加mapper接口(记得添加mapper扫描)

@Repository
public interface UserMapper extends BaseMapper<User> {
}

7、添加UserService接口

public interface UserService {
    //用户登录
    User getUserInfoByName(String name);
}

8、实现UserService接口

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;
    @Override
    public User getUserInfoByName(String name) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name",name);
        User user = userMapper.selectOne(queryWrapper);
        return user;
    }
}

9、自定义一个登录认证MyRealm

/*
* 自定义登录认证
* */
@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    //自定义授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //登录认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1、获取用户信息
        String name = authenticationToken.getPrincipal().toString();

        //2、调用业务层获取数据库用户信息
        User user = userService.getUserInfoByName(name);
        //3、非空判断,封装返回数据
        if (user!=null){
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    user.getName(),
                    //md5加的盐
                    ByteSource.Util.bytes("cdy"),
                    authenticationToken.getPrincipal().toString()
            );
            return info;
        }
        return null;
    }
}

10、创建Shiro核心类ShiroConfig

@Configuration
public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        //1、创建defaultWebSecurityManager对象
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //2、创建加密对象
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //2.1采用md5加密
        matcher.setHashAlgorithmName("md5");
        //2.2迭代加密次数
        matcher.setHashIterations(3);
        //3、将加密对象存储到myRealm中
        myRealm.setCredentialsMatcher(matcher);
        //4、将myRealm存入defaultWebSecurityManager对象中
        defaultWebSecurityManager.setRealm(myRealm);
        //5、返回
        return defaultWebSecurityManager;
    }

    //配置Shiro内置过滤器拦截范围
    @Bean
    public DefaultShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        //设置不认证可以访问的资源
        definition.addPathDefinition("/myController/userLogin", "anon");
        //设置需要进行登录认证的拦截范国
        definition.addPathDefinition("/**", "authc");
        return definition;

    }
}

11、实现访问接口controller

@Controller
@RequestMapping("/myController")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/userLogin")
    @ResponseBody
    public String userLogin(String name , String pwd){
        System.out.println(name);
        System.out.println(pwd);
        //1、获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        //2、获取token对象:用户名及密码
        AuthenticationToken token = new UsernamePasswordToken(name,pwd);
        //4、完成登录
        try{
            subject.login(token);
            System.out.println("登录成功");
            return "登录成功";

        } catch(UnknownAccountException e ){
            e.printStackTrace();
            System.out.println("用户不存在");
            return "用户不存在";
        }catch (IncorrectCredentialsException e ){
            e.printStackTrace();
            System.out.println("密码错误");
            return "密码错误";
        }
        catch (AuthenticationException e){
            e.printStackTrace();
            return "登录失败";
        }


    }

}

12、添加登录相关前端页面

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>Shiro登录认证</h1></br>
<form action="/myController/userLogin">
    <div>用户名:<input type="text" name="name" value=""></div>
    <div>密码:<input type="password" name="pwd" value=""></div>
    <div> <input type="submit" value="登录"></div>
</form>
</body>
</html>

main.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<h1>Shiro登录主页</h1><br>
<h2>登录用户为:</h2><span th:text="${session.user}"></span>
</body>
</html>

error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面出错</title>
</head>
<body>
<h1>页面出错</h1>
</body>
</html>

13、改造UserController

@Controller
@RequestMapping("/myController")
public class UserController {
    @Autowired
    private UserService userService;

    /*
    * 登录跳转页面
    * */
    @GetMapping("login")
    public String login(){
        return  "login";
    }

/*登录认证*/
    @RequestMapping("/userLogin")
    public String userLogin(String name , String pwd,HttpSession httpSession ){
        System.out.println(name);
        System.out.println(pwd);
        //1、获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        //2、获取token对象:用户名及密码
        AuthenticationToken token = new UsernamePasswordToken(name,pwd);
        //4、完成登录
        try{
            subject.login(token);
            httpSession.setAttribute("user",token.getPrincipal().toString());
            System.out.println("登录成功");
            return "main";

        } catch(UnknownAccountException e ){
            e.printStackTrace();
            System.out.println("用户不存在");
            return "error";
        }catch (IncorrectCredentialsException e ){
            e.printStackTrace();
            System.out.println("密码错误");
            return "error";
        }
        catch (AuthenticationException e){
            e.printStackTrace();
            return "error";
        }


    }

}

注意:

二、授权角色验证

1、授权

用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判 断。 这个工具就是Realm的doGetAuthorizationInfo方法进行判断。

触发权限判断的有两种 方式

(1) 在页面中通过shiro************属性判断

(2) 在接口服务中通过注解@Requires************进行判断

2、后端接口服务注解

​ 通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加 在业务方法上,一般加在控制器方法上。常用注解如下:

(1)@RequiresAuthentication

验证用户是否登录,等同于方法subject.isAuthenticated()

(2)@RequiresUser

验证用户是否被记忆: 登录认证成功subject.isAuthenticated()为true 登录后被记忆subject.isRemembered()为true

(3)@RequiresGuest

验证是否是一个guest的请求,是否是游客的请求 此时subject.getPrincipal()为null

(4)@RequiresRoles

验证subject是否有相应角色,有角色访问方法,没有则会抛出异常 AuthorizationException。

(5)@RequiresPermissions

验证subject是否有相应权限,有权限访问方法,没有则会抛出异常 AuthorizationException。

3、创建角色(role)表

CREATE TABLE `role` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `name` VARCHAR(30) DEFAULT NULL COMMENT '角色名', 
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述', 
 `realname` VARCHAR(20) DEFAULT NULL COMMENT '角色显示名', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表'; 

4、创建中间表(role_user)

CREATE TABLE `role_user` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `uid` BIGINT(20) DEFAULT NULL COMMENT '用户 id', 
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色用户映射表'; 

5、修改 MyRealm 方法

 //自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 //获取当前用户身份信息 
 String principal = 
principalCollection.getPrimaryPrincipal().toString(); 
 //调用接口方法获取用户的角色信息 
 List<String> roles = userService.getUserRoleInfo(principal); 
 System.out.println("当前用户角色信息:"+roles); 
 //创建对象,存储当前登录的用户的权限和角色 
 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
 //存储角色 
 info.addRoles(roles); 
 //返回 
 return info; 
} 

6、添加 UserController 方法,并添加验证角色注解

 //登录认证验证角色 
@RequiresRoles("admin") 
@GetMapping("userLoginRoles") 
@ResponseBody 
public String userLoginRoles() { 
 System.out.println("登录认证验证角色"); 
 return "验证角色成功"; 
}

7、main.html页面添加

<br> 
 <a href="/myController/userLoginRoles">测试授权</a> 

8、UserMapper添加方法

@Repository 
public interface UserMapper extends BaseMapper<User> { 
 @Select("SELECT NAME FROM role WHERE id IN (SELECT rid FROM 
role_user WHERE uid=(SELECT id FROM USER WHERE NAME=#{principal}))") 
 List<String> getUserRoleInfoMapper(@Param("principal") String 
principal); 
}

9、UserService添加接口方法

//获取用户的角色信息 
    List<String> getUserRoleInfo(String principal);

10、UserServiceImpl 添加

  //获取用户的角色信息
    @Override
    public List<String> getUserRoleInfo(String principal) {
        return userMapper.getUserRoleInfoMapper(principal);
    }

三、授权权限验证

1、创建权限表

CREATE TABLE `permissions` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `name` VARCHAR(30) DEFAULT NULL COMMENT '权限名', 
 `info` VARCHAR(30) DEFAULT NULL COMMENT '权限信息', 
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='权限表';

2、创建角色权限表

CREATE TABLE `role_ps` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id', 
 `pid` BIGINT(20) DEFAULT NULL COMMENT '权限 id', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色权限映射表'

3、UserMapper添加方法

@Select({ 
 "<script>", 
 "select info FROM permissions WHERE id IN ", 
 "(SELECT pid FROM role_ps WHERE rid IN (", 
 "SELECT id FROM role WHERE NAME IN ", 
 "<foreach collection='roles' item='name' open='(' 
separator=',' close=')'>", 
 "#{name}", 
 "</foreach>", 
 "))", 
 "</script>" 
}) 
List<String> getUserPermissionInfoMapper(@Param("roles")List<String> 
roles);

4、UserService添加接口方法

  //获取用户角色的权限信息 
    List<String> getUserPermissionInfo(List<String> roles);

5、UserServiceImpl 添加

//获取用户角色的权限信息 
@Override 
public List<String> getUserPermissionInfo(List<String> roles) { 
 return userMapper.getUserPermissionInfoMapper(roles); 
}

6、修改 MyRealm 方法

//自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 //获取当前用户身份信息 
 String principal = 
principalCollection.getPrimaryPrincipal().toString(); 
 //调用接口方法获取用户的角色信息 
 List<String> roles = userService.getUserRoleInfo(principal); 
 System.out.println("当前用户角色信息:"+roles); 
 //调用接口方法获取用户角色的权限信息 
 List<String> permissions = 
 
userService.getUserPermissionInfo(roles); 
 System.out.println("当前用户权限信息:"+permissions); 
 //创建对象,存储当前登录的用户的权限和角色 
 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
 //存储角色 
 info.addRoles(roles); 
 //存储权限信息 
 info.addStringPermissions(permissions); 
 //返回 
 return info; 
}

7、添加 UserController 方法

//登录认证验证权限 
@RequiresPermissions("user:delete") 
@GetMapping("userPermissions") 
@ResponseBody 
public String userLoginPermissions() { 
 System.out.println("登录认证验证权限"); 
 return "验证权限成功"; 
}

8、main.html页面添加

<br>
<a href="/myController/userPermissions">测试授权-权限验证</a> 

四、授权验证异常处理

创建异常类

@ControllerAdvice 
public class PermissionsException { 
 @ResponseBody 
 @ExceptionHandler(UnauthorizedException.class) 
 public String unauthorizedException(Exception ex){ 
 return "无权限"; 
 } 
 
 @ResponseBody 
 @ExceptionHandler(AuthorizationException.class) 
 public String authorizationException(Exception ex){ 
 return "权限认证失败"; 
 } 

五、启动测试(自测)

更多内容获取评论区私信

  • 34
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值