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();
    }
- 
- 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>
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号