shiro具体实现


1)登录拦截


shiro的核心过滤器:


  • controller:

  • ShiroConfig:

  • 目录:


2)用户认证


  • login.html:
<body>

<h1>登录页面</h1>

<hr>

<p th:text="${msg}" style="color: red"></p>

<form th:action="@{/login}">
    <p>用户名: <input type="text" name="username"></p>
    <p>密码: <input type="password" name="password"></p>
    <p><input type="submit" ></p>
</form>

</body>
  • cotroller:
    @RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取当前用户
        Subject subject= SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            subject.login(token);//执行登录方法
            return "index";//登陆成功则转到index.html页面

        } catch (UnknownAccountException e) { //用户不存在的异常
            model.addAttribute("msg","用户名错误!");
            return "login";
        } catch (IncorrectCredentialsException e) { //密码错误异常
            model.addAttribute("msg", "密码错误!");
            return "login";
        }


    }
  • UserRealm:
//自定义的realm
public class UserRealm extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权doGetAuthorizationInf");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证doGetAuthorizationInf");

        //用户名,密码  应该到数据库中取,这里为了方便,自己伪造一个
        String name="root";
        String password="123456";

        UsernamePasswordToken userToken=(UsernamePasswordToken)authenticationToken;

        //用户名认证:如果前端获取的用户名和设定的不一致则返回null
        if (!userToken.getUsername().equals(name)){
            return null;//return null会抛出UnknownAccountException异常
        }
        //密码认证,不用自己写,由shiro来完成
        return new SimpleAuthenticationInfo("",password,"");
    }
}

  • 运行测试:



3)整合MyBatis


  • 1.首先需要导入对应的依赖
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

  • 2.连接mysql数据库


  • 3.写一个yml

直接拷贝之前博客写好的yml内容:https://www.cnblogs.com/kakafa/p/15960412.html

spring:
  datasource:
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatistest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
    type: com.alibaba.druid.pool.DruidDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500



  • 4.配置mybatis,并且完成pojo和mapper的建立和编写

UserRealm:

//自定义的realm
public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权doGetAuthorizationInf");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证doGetAuthorizationInf");



        UsernamePasswordToken userToken=(UsernamePasswordToken)authenticationToken;

        //连接真实数据库
        User user = userService.queryByUsername(userToken.getUsername());
        if (user==null){ //没有这个人
            return null;
        }

        //密码认证,不用自己写,由shiro来完成
        return new SimpleAuthenticationInfo("",user.getPwd(),"");
    }
}

测试结果:


4)请求授权实现


ShiroConfig:

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("dwsm") DefaultWebSecurityManager sm){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(sm);

        //添加shiro的内置过滤器
        Map<String,String> filterMap = new LinkedHashMap<>();

        //授权 未授权的情况下会跳转到401错误页面,即提示未授权页面;也可以自定义未授权提示:bean.setUnauthorizedUrl("/unauth");
        filterMap.put("/user/add","perms[user:add]");//"perms[user:add]"必须是user这个用户并且偶对add的访问权限

        filterMap.put("/user/*","authc");//需要认证了才能访问user目录下的页面
        bean.setFilterChainDefinitionMap(filterMap);
        bean.setLoginUrl("/toLogin");//如果没有权限,则跳转到登录页面,这里是设置登录页面的请求地址

        //未授权页面
        bean.setUnauthorizedUrl("/unauth");

        return bean;
    }


    //DefaultWebSecurityManager
    @Bean(name = "dwsm")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建 realm 对象  需要自定义一个类UserRealm
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

}


这一步是给用户授予权限:

UserRealm:

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权doGetAuthorizationInf");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");

        return info;
    }

重启测试后,发现所有能登录的用户都可以正常访问add页面了。但是实际情况应该书部分用户有授权而不是所有用户,因此这里做如下改动:

给user表增加一个perms字段:相对应的pojo实体类也得改



5)整合thymeleaf


  • 1.先导入pom依赖
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.1.0</version>
        </dependency>


  • 2.ShiroConfig:
    //整合shiroDialect:用来整合shiroThemeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

    1. index.html:使得首页的部分连接值对拥有相应授权的用户显示
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>

<h1>首页</h1>

<p shiro:notAuthenticated>
    <a th:href="@{/toLogin}">登录</a>
</p>

<p th:text="${msg}"></p>

<!--shiro:hasPermission="user:add"这里冒号会报错,加一层单引号即可-->
<div shiro:hasPermission="'user:add'">
    <a th:href="@{/user/add}">add</a>
</div>

<div shiro:hasPermission="'user:update'">
    <a th:href="@{/user/update}">update</a>
</div>

</body>
</html>


posted @   卡卡发  阅读(263)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示