springboot+shiro+mybatis maven项目整合

springboot+shiro+mybatis安全框架整合

springboot+shiro+mybatis maven项目整合

1.引入依赖

<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.10</version>
		</dependency>
		<!--数据库连接依赖-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!--durid的数据源-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
		</dependency>
		<!--mybits依赖-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.4</version>
		</dependency>


		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--thymeleaf依赖-->
		<dependency>
			<groupId>org.thymeleaf</groupId>
			<artifactId>thymeleaf-spring5</artifactId>
		</dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-java8time</artifactId>
		</dependency>
		<!--thymeleaf整合shiro依赖-->
		<dependency>
			<groupId>com.github.theborakompanioni</groupId>
			<artifactId>thymeleaf-extras-shiro</artifactId>
			<version>2.0.0</version>
		</dependency>

2、创建实体类



public class User implements Serializable{
    private int id;
    private String username;
    private String password;
    private String role;

    public User() {
    }

    public User(int id, String username, String password, String role) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.role = role;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

3、创建realm类


public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();
        System.out.println(currentUser.getUsername());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //多角色我在数据的是用逗号隔开的字符串,认证操作跟你配置的数据库做处理,但是 都是用info.addStringPermission(‘角色’)来认证
        String[] split = currentUser.getRole().split(",");
        for (String s : split) {
            info.addStringPermission(s);
        }

        return info;
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthenticationInfo");
        
       /* 
        此代码是不链接数据库的测试代码
        String username = "root";
        String password = "root";
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        System.out.println(userToken.getUsername());
        if (!username.equals(userToken.getUsername())){
            return null;
        }*/
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        //System.out.println(userToken.getUsername());
       //链接真是数据库
        User user = userService.findByName(userToken.getUsername());
        if (user == null){
            return null;
        }
        //将实体类存到shiro的回话当中,用于页面展示登录用户
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

4、创建shiro控制类

@Configuration
public class ShiroConfig {


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



        /*

         anon:  无需认证就可以访问
         authc: 必须认证才能访问
         user:  必须拥有记住我功能才能用
         perms:  拥有对某个资源的权限才能访问
         role:  拥有某个角色权限才能访问
          filterMap.put("/user/add","authc");//设置认证链接
          filterMap.put("/user/update","authc");//设置认证链接
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        filterMap.put("/user/add","perms[root]");
        filterMap.put("/user/update","perms[update]");
        filterMap.put("/user/*","authc");//设置认证链接

        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
        filterFactoryBean.setLoginUrl("/toLogin");

        //设置未授权跳转
//        filterFactoryBean.setUnauthorizedUrl("未授权跳转的url");
        return filterFactoryBean;
    }

    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myrealm") MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }
    //创建realm对象
    @Bean(name = "myrealm")
    public MyRealm myRealm(){
        return new MyRealm();
    }

    //配置thymeleaf和shiro的整合
    @Bean()
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }



    /**
     * cookie对象;
     * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
      /*  //System.out.println("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        return simpleCookie;*/
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:

        //setcookie()的第七个参数
        //设为true后,只能通过http访问,javascript无法访问
        //防止xss读取cookie
        simpleCookie.setHttpOnly(true);
        simpleCookie.setPath("/");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(2592000);
        return simpleCookie;
    }

    /**
     * cookie管理对象;
     * rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        //System.out.println("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
        return cookieRememberMeManager;
    }

    /**
     * FormAuthenticationFilter 过滤器 过滤记住我
     * @return
     */
    @Bean
    public FormAuthenticationFilter formAuthenticationFilter(){
        FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
        //对应前端的checkbox的name = rememberMe
        formAuthenticationFilter.setRememberMeParam("rememberMe");
        return formAuthenticationFilter;
    }


}

5、编写controller 登陆退出方法

@Controller
public class MyController {

    @RequestMapping("login")
    public String login(Model model,String username,String password,boolean rememberMe){

        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(username,password,rememberMe);
        try {
            subject.login(token);
            return "index";
        } catch (UnknownAccountException uae) {
            model.addAttribute("msg","用户名错误");
            return "loginView";
        }catch (IncorrectCredentialsException ice){
            model.addAttribute("msg","密码错误");
            return "loginView";
        }

    }

    @RequestMapping("quite")
    public String quite(){
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.removeAttribute("loginame");
        subject.logout();
        return "index";
    }
}

在这里,基础的页面跳转我是做了一个前端控制器的控制类,大家也可以在controller里面添加跳转的url

@Configuration
public class WebConfig implements WebMvcConfigurer{

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/user/add.html").setViewName("/user/add");
        registry.addViewController("/user/update.html").setViewName("user/update");
        registry.addViewController("/user/add").setViewName("/user/add");
        registry.addViewController("/user/update").setViewName("user/update");
        registry.addViewController("/toLogin").setViewName("loginView");
    }
}

6、编写业务层(ps:这是两个类)


public interface UserService {
    User findByName(String username);
}

@Service
public class UserServiceImlp implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public User findByName(String username) {
        return userMapper.findByName(username);
    }
}

7、编写持久层接口

@Repository
@Mapper
public interface UserMapper {
    User findByName(String username);
}

8、编写sql

<?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.shiro.mapper.UserMapper">


    <select id="findByName" resultType="user">
        select * FROM `user` WHERE username = #{username}
    </select>

</mapper>

数据库配置
数据库字段配置

9、yml文件配置

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    username: root
    password: 123456
    #serverTimezone=UTC时区错误
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
    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,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  #热部署配置
  devtools:
    restart:
      enabled: true
      additional-paths: src/main/java
      exclude: WEB-INF/**
  freemarker:
    cache: false    #关闭thymeleaf缓存

mybatis:
  type-aliases-package: com.yipengzhan.pojo #实体类包扫描
  mapper-locations: classpath:com/shiro/mapper/*.xml #如果mybatis的xml文件必须与持久层接口文件路径一致

文件存放路径
文件路径
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>
</head>
<body>
<!--验证当前用户是否为“访客”,即未认证(包含未记住)的用户。-->
<shiro:guest>
    <a th:href="@{/toLogin}">登录</a>
</shiro:guest>
<!--认证通过或已记住的用户-->
<shiro:user>
    欢迎<shiro:principal property="username"/>
    <a th:href="@{/quite}">退出</a>
</shiro:user>

<!--验证当前用户是否拥有指定权限。  -->
<div shiro:hasPermission="root">
<a th:href="@{/user/add}">add</a>
</div>||
<div shiro:hasPermission="update">
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html>

loginview.html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<p th:text="${msg}" style="color: red"></p>
<form th:action="@{/login}" method="post">
    用户名:<input name="username"><br>
    密码:<input name="password"><br>
    <input type="checkbox" name="rememberMe" value="true"/>记住我<br>
    <input type="submit">
</form>
</body>
</html>

我用的springboot的版本的是2.3.3,如果通过以上的没有实现整合,建议更换一下springbot版本


版权声明:本文为weixin_45815347原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。