SpringBoot集成Shiro

网友投稿 305 2022-11-28

SpringBoot集成Shiro

SpringBoot集成Shiro

​​简介​​​​功能简介​​​​Shiro架构​​​​SpringBoot集成​​

​​SpringBoot整合Shiro环境搭建​​​​测试环境​​​​编写导入配置类​​​​shiro实现登录拦截​​​​shiro实现用户验证​​​​shiro整合Mybatis​​​​shiro整合Thymeleaf​​

简介

Apache shiro 是Java的安全(权限)框架。Shiro可以可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JAVAEE环境。Shiro可以完成:认证授权、加密、会话管理,与web集成,缓存等。

功能简介

Authentications:身份证/ 登录,验证用户是不是拥有相应的身份Authorization:授权,即授权验证,验证某个用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限Session Manager:会话管理,即用户登陆后就是一次会话,在没有退出之前,他的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web环境的;Cryptography : 加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;Cryptography :加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;Caching :缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;Concurrency : Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;Testing :提供测试支持;Run As :允许-个用户假装为另-个用户(如果他们允许)的身份进行访问;Remember Me :记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了;

Shiro架构

SpringBoot集成

SpringBoot整合Shiro环境搭建

org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-web RELEASE compile org.apache.shiro shiro-spring-boot-web-starter 1.7.1 org.mortbay.jetty jetty 6.1.25

测试环境

新建一个controller页面

import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class MyController { @RequestMapping({"/","index"}) public String toIndex(Model model){ model.addAttribute("msg","hello,Shiro"); return "index"; } @RequestMapping("/user/add") public String add(){ return "user/add"; } @RequestMapping("/user/update") public String update(){ return "user/update"; }}

新建index.html页面

Title

首页


add update

新建一个add.html页面

Title

add

新建一个update.html页面

Title

update

编写导入配置类

编写一个自定义类UserRealm

import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;public class UserRealm extends AuthorizingRealm { // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权doGetAuthorizationInfo"); return null; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("认证:=》doGetAuthenticationInfo"); return null; }}

编写配置ShiroConfig,注意启动失败,添加​​name = "shiroFilterFactoryBean"​​

创建realm对象,需要自定义类DefaultWebSecurityManagerShiroFilterFactoryBean

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class ShiroConfig { //ShrioFilterFactoryBean @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); // 设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); return bean; } //DefaultWebSecurityManager:2 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联UserRealm securityManager.setRealm(userRealm); return securityManager; } //创建realm 对象,需要自定义类:1// @Bean(name = "userRealm") @Bean public UserRealm userRealm(){ return new UserRealm(); }}

shiro实现登录拦截

在​​ShiroConfig​​​中的​​getShiroFilterFactoryBean​​方法中添加如下配置

anon: 无需认证就可以访问authc: 必须认证了才能访问user: 必须拥有记住我功能才能用perms: 拥有对某个资源的权限才能访问role: 拥有某个角色权限

@Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); // 设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager);// 添加shiro的内置过滤器 /** * anon:无需认证直接访问 * authc:必须认证才能访问 * user:必须拥有 记住我 功能才能使用 * perms:拥有对某个资源的权限才能拥有 * role:拥有某个角色权限才能访问 */ Map filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); //设置登录的请求 bean.setLoginUrl("/toLogin"); return bean; }

添加拦截成功页面

登录页面login.html

Title

登录


用户名:

密码:

在MyController中添加

@RequestMapping("/toLogin")public String toLogin(){ return "login";}

在​​ShiroConfig​​中的​​getShiroFilterFactoryBean​​方法中添加如下配置

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

shiro实现用户验证

在​​MyController​​中编写用户提交表单之后处理

@RequestMapping("/login")public String login(String username,String password,Model model){ // 获取当前用户 Subject subject = SecurityUtils.getSubject(); // 封装用户的登录数据 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); try { subject.login(usernamePasswordToken); // 执行登录的方法,如果没用一场就说明ok了 return "index"; } catch (UnknownAccountException e) { //用户名不存在 model.addAttribute("msg","用户名错误!"); return "login"; } catch (IncorrectCredentialsException e){ //密码不存在 model.addAttribute("msg","密码错误!"); return "login"; }}

​​login.html​​的修改

Title

登录


用户名:

密码:

用户输入登录信息用户认证编写​​UserRealm​​中的认证​​(doGetAuthenticationInfo)​​

//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("认证:=》doGetAuthenticationInfo"); // 用户名,密码 数据库中取 String name = "root"; String password = "123456"; UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; if(!token.getUsername().equals(name)){ return null; // 抛出异常 UnknownAccountException } // 密码认证,shiro做 return new SimpleAuthenticationInfo("",password,""); // return null;}

shiro整合Mybatis

导入依赖

mysql mysql-connector-java 8.0.28 log4j log4j 1.2.17 com.alibaba druid 1.1.12 org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.2

配置文件​​application.yml​​的编写

spring: datasource: username: root password: root #?serverTimezone=UTC解决时区的报错 url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver 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 地址: filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties:

mybatis.type-aliases-package=com.stefan.pojomybatis.mapper-locations=classpath:mapper/*.xml

User 类的编写

package com.stefan.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructorpublic class User { private int id; private String name; private String pwd;}

​​UserMapper.xml​​映射

​​UserService​​接口实现

package com.stefan.service;import com.stefan.pojo.User;public interface UserService { public User queryUserByName(String name);}

​​UserServiceImpl​​业务逻辑

package com.stefan.service;import com.stefan.mapper.UserMapper;import com.stefan.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; @Override public User queryUserByName(String name) { return userMapper.queryUserByName(name); }}

测试环境

package com.stefan;import com.stefan.pojo.User;import com.stefan.service.UserServiceImpl;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTestclass ShiroSpringbootApplicationTests { @Autowired UserServiceImpl userService; @Test void contextLoads() { User stefan = userService.queryUserByName("stefan"); System.out.println(stefan); }}

​​UserRealm​​连接真实数据库

//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("认证:=》doGetAuthenticationInfo"); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 连接真实数据库 User user = userService.queryUserByName(token.getUsername()); // 密码认证,shiro做 if(user == null){ return null;// 抛出异常 UnknownAccountException } return new SimpleAuthenticationInfo("",user.getPwd(),"");

@RequestMapping("/noauth")@ResponseBodypublic String unauthorized(){ return "未经授权无法访问此页面";}ShiroConfig中的getShiroFilterFactoryBean方法中添加//设置未授权页面bean.setUnauthorizedUrl("/noauth");

//自定义的UserRealm extends AuthorizingRealmpublic class UserRealm extends AuthorizingRealm { @Autowired UserService userService; // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权doGetAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 拿到当前登录的这个对象 Subject subject = SecurityUtils.getSubject(); User currentUser = (User) subject.getPrincipal(); // 拿到user对象 //设置当前对象的权限 info.addStringPermission(currentUser.getPerms()); return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("认证:=》doGetAuthenticationInfo"); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 连接真实数据库 User user = userService.queryUserByName(token.getUsername()); // 密码认证,shiro做 if(user == null){ return null;// 抛出异常 UnknownAccountException } return new SimpleAuthenticationInfo(user,user.getPwd(),""); }}

shiro整合Thymeleaf

shiro-thymeleaf整合包导入——​​官网​​

com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0

在ShiroConfig中整合ShiroDialect

// 整合ShiroDialect:用来整合shiro thymeleaf@Beanpublic ShiroDialect getShiroDialect(){ return new ShiroDialect();}

index.html页面

Title

首页


ShiroConfig

package com.stefan.config;import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.Map;@Configurationpublic class ShiroConfig { //ShrioFilterFactoryBean @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); // 设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); // 添加shiro的内置过滤器 /* * anon:无需认证就可以访问 * authc:必须认证了才能访问 * user:必须拥有 记住我 功能才能用 * perms:拥有对某个资源的权限才能访问 * role:拥有某个角色权限才能访问 * * */ Map filterChainDefinitionMap = new LinkedHashMap<>(); //授权,正常情况下,没有授权会跳转到未授权页面 filterChainDefinitionMap.put("/user/add","perms[user:add]"); filterChainDefinitionMap.put("/user/update","perms[user:update]"); // 登录拦截// filterChainDefinitionMap.put("/user/add","authc");// filterChainDefinitionMap.put("/user/update","authc"); filterChainDefinitionMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); //设置登录的请求 bean.setLoginUrl("/toLogin"); //设置未授权页面 bean.setUnauthorizedUrl("/noauth"); return bean; } //DefaultWebSecurityManager:2 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联UserRealm securityManager.setRealm(userRealm); return securityManager; } //创建realm 对象,需要自定义类:1// @Bean(name = "userRealm") @Bean public UserRealm userRealm(){ return new UserRealm(); } // 整合ShiroDialect:用来整合shiro thymeleaf @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); }}

UserRealm

package com.stefan.config;import com.stefan.pojo.User;import com.stefan.service.UserService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;//自定义的UserRealm extends AuthorizingRealmpublic class UserRealm extends AuthorizingRealm { @Autowired UserService userService; // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权doGetAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// info.addStringPermission("user:add");// info.addStringPermission("user:update"); // 拿到当前登录的这个对象 Subject subject = SecurityUtils.getSubject(); User currentUser = (User) subject.getPrincipal(); // 拿到user对象 //设置当前对象的权限 info.addStringPermission(currentUser.getPerms());// return null; return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("认证:=》doGetAuthenticationInfo"); // 用户名,密码 数据库中取// String name = "root";// String password = "123456";////// UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;// 连接真实数据库User user = userService.queryUserByName(token.getUsername());// 密码认证,shiro做if(user == null){ return null;// 抛出异常 UnknownAccountException}

package com.stefan.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class MyController { @RequestMapping({"/","index"}) public String toIndex(Model model){ model.addAttribute("msg","hello,Shiro"); return "index"; } @RequestMapping("/user/add") public String add(){ return "user/add"; } @RequestMapping("/user/update") public String update(){ return "user/update"; } @RequestMapping("/toLogin") public String toLogin(){ return "login"; } @RequestMapping("/login") public String login(String username,String password,Model model){ // 获取当前用户 Subject subject = SecurityUtils.getSubject(); // 封装用户的登录数据 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); try { subject.login(usernamePasswordToken); // 执行登录的方法,如果没用一场就说明ok了 return "index"; } catch (UnknownAccountException e) { //用户名不存在 model.addAttribute("msg","用户名错误!"); return "login"; } catch (IncorrectCredentialsException e){ //密码不存在 model.addAttribute("msg","密码错误!"); return "login"; } } @RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未经授权无法访问此页面"; } }

pom依赖

Title

首页


add.html

Title

add

login.html

Title

登录


用户名:

密码:

update.html

Title

update

User实体类

package com.stefan.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructorpublic class User { private int id; private String name; private String pwd; private String perms;}

UserService

package com.stefan.service;import com.stefan.pojo.User;public interface UserService { public User queryUserByName(String name);}

UserServiceImpl

package com.stefan.service;import com.stefan.mapper.UserMapper;import com.stefan.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; @Override public User queryUserByName(String name) { return userMapper.queryUserByName(name); }}

UserMapper

package com.stefan.mapper;import com.stefan.pojo.User;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;@Repository@Mapperpublic interface UserMapper { public User queryUserByName(String name);}

UserMapper.xml

tory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; @Override public User queryUserByName(String name) { return userMapper.queryUserByName(name); } }

- UserMapper```javapackage com.stefan.mapper;import com.stefan.pojo.User;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;@Repository@Mapperpublic interface UserMapper { public User queryUserByName(String name);}

UserMapper.xml

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:全面理解Java中的引用传递和值传递
下一篇:串口(DB9)转RJ45的转接头的接线
相关文章

 发表评论

暂时没有评论,来抢沙发吧~