shiro安全框架使用整合thymeleaf以及SpringBoot

导入相关依赖

<dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.8.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

编写Shiro配置类

首先是Realm

//权限操作
//自定义的Realm

public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println ("执行了=》授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo ();
        //info.addStringPermission ("user:add");
        //拿到当前登录的对象
        Subject subject = SecurityUtils.getSubject ();
        User currentUser = (User) subject.getPrincipal (); // 拿到user对象
        info.addStringPermission (currentUser.getPerms ());
        return info;
    }
    //认证
    @Override // AuthenticationToken token 来自于MyController中的 UsernamePasswordToken token = new UsernamePasswordToken (username,password);
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println ("执行了=》认证doGetAuthenticationInfo");

        //用户名,密码  数据库中取
        UsernamePasswordToken userToken= (UsernamePasswordToken) token;

        User user = userService.queryUserByName (userToken.getUsername ());
        if(user==null)  //用户名出错
        {
            return null;
        }
        String password=user.getPwd ();
        //密码可以加密:MD5  e10adc3949ba59abbe56e057f20f883e
        //           MD5盐值加密   e10adc3949ba59abbe56e057f20f883e+username/
        //密码认证:shiro来封装
        return new SimpleAuthenticationInfo (user,password,"");   //传入user对象给授权,传入密码给shiro判断
    }
}

ShiroConfig


//请求过滤
@Configuration
public class ShiroConfig {
    //第一步 创建realm对象,需要自定义
    @Bean(name = "userRealm")
    public UserRealm userRealm(){
        return new UserRealm ();
    }
    //第二步 DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager ();
        //关联Realm
        securityManager.setRealm (userRealm);
        return securityManager;
    }
    //第三步 ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager)
    {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean ();
        //设置安全管理器
        bean.setSecurityManager (defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
        * anon:无需认证就可以访问
        * authc:必须认证才可以访问
        * user:必须拥有记住我(remember me)才能用
        * perms:拥有对某个资源的权限才能访问
        * role:拥有某个角色全选才能访问
        * */
        //拦截
        Map<String,String> FilterChainDefinitionMap=new LinkedHashMap<> ();
        /*FilterChainDefinitionMap.put ("/user/add","authc");
        FilterChainDefinitionMap.put ("/user/update","authc");*/
        //授权  正常情况下,没有授权会跳转到未授权页面
        FilterChainDefinitionMap.put ("/user/add","perms[user:add]");
        FilterChainDefinitionMap.put ("/user/update","perms[user:update]");
        //设置未授权页面
        bean.setUnauthorizedUrl ("/noauth");
        bean.setFilterChainDefinitionMap (FilterChainDefinitionMap);

        //设置登录请求
        bean.setLoginUrl ("/toLogin");

        return bean;
    }
    //整合shiroDialect 用来整合shiro-theymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect ();
    }
}

Controller层

/*
* Subject   用户
* SecurityManager  管理用户
* Realm     连接数据
* */
/*导入整合spring的包*/
@Controller
public class MyController {
    @RequestMapping({"/","index"})
    public String toIndex(Model model){
        model.addAttribute ("msg","hello shiro");
        return "index";
    }
    @RequestMapping("/user/add")
    public String addUser()
    {
        return "user/addUser";
    }
    @RequestMapping("/user/update")
    public String updateUser()
    {
        return "user/updateUser";
    }
    @RequestMapping("/toLogin")
    public String tologin()
    {
        return "login";
    }
    @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); //执行登陆方法,没有异常就ok
            Subject currentSubject = SecurityUtils.getSubject ();
            Session session = currentSubject.getSession ();
            session.setAttribute ("loginUser",username);
            return "/index";
        } catch (UnknownAccountException e) {  //用户名不存在
            model.addAttribute ("msg","用户名错误");
            return "login";
        } catch (IncorrectCredentialsException ice) {   //异常:密码不对
            model.addAttribute ("msg","密码错误");
            return "login";
        } catch (LockedAccountException lae) {          //异常:用户名被锁定
            model.addAttribute ("msg","用户名被锁定");
            return "login";
        }
    }
    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized()
    {
        return "未经授权无法访问";
    }
}

数据库层不做过多解释就先放一个mapper文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ji.mapper.UserMapper">
    <select id="queryUserByName" parameterType="String" resultType="com.ji.pojo.User">
        select * from `user`
        where name=#{name}
    </select>
</mapper>

数据库配置

spring:
  datasource:
    username: root
    password: root
    #假如时区报错,就增加一个时区的配置就ok了,serverTimezone=UTC
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #SpringBoot默认是不注入这些的,需要自己绑定
    #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.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis:
  mapper-locations: classpath:mapper/*.xml

html文件

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>

<div th:if="${session.loginUser==null}">
    <a th:href="@{/toLogin}">登录</a>
</div>
<p th:text="${msg}"></p>
<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>

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<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>
</html>

shiro可进行密码加密主要继承此接口

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;

public interface CredentialsMatcher {

    /**
     * Returns {@code true} if the provided token credentials match the stored account credentials,
     * {@code false} otherwise.
     *
     * @param token   the {@code AuthenticationToken} submitted during the authentication attempt
     * @param info the {@code AuthenticationInfo} stored in the system.
     * @return {@code true} if the provided token credentials match the stored account credentials,
     *         {@code false} otherwise.
     */
    boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);

}

我们可以自定义密码加密方式也可以使用如下加密方法

posted @ 2021-12-04 21:32  一刹流云散  阅读(58)  评论(0编辑  收藏  举报