目录
1.springboot整合shiro-----认证(登录)
1.1.创建springboot项目
1.2.引依赖
1.3.修改application配置文件
1.4.创建实体类
1.5.创建dao层
1.6.创建service层
1.7.编写realm
1.8.创建vo层
1.9.创建Controller层
1.10. 创建shiro的配置类
1.11.创建登录页面与登录成功页面
1.12.测试
2.springboot整合shiro--授权(权限)
2.1.修改Realm
2.2.创建Service
2.3.创建PermissionDao
2.4.创建PermissionDao.xml
2.5.创建UserController
2.6.修改登录成功页面
2.7.添加依赖
2.8.ShiroConfig修改
测试
2.9.权限不足时跳转到一个页面
3.springboot整合shiro----前后端分离
创建Result
3.1.登录成功或失败---返回json数据
3.2.权限不足时---返回json数据
3.3.未登录时---返回json数据
4.shiro权限对象缓存到redis中
5.使用Swagger2接口文档测试
org.springframework.boot spring-boot-starter-web mysql mysql-connector-java com.baomidou mybatis-plus-boot-starter 3.5.1 org.springframework.boot spring-boot-starter-thymeleaf org.projectlombok lombok org.apache.shiro shiro-spring-boot-starter 1.7.0 org.springframework.boot spring-boot-starter-test test
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql:///shiro?serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456789 #日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus.mapper-locations=classpath:/mapper/*.xml #thymeleaf的视图解析器 spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html #定义shiro的加密算法 shiro.hashAlgorithmName=MD5 shiro.hashIterations=1024
@Data public class Permission { @TableId(type = IdType.AUTO) private Integer perid; private String pername; private String percode; }
@Data public class User implements Serializable { @TableId(type = IdType.AUTO) private Integer userid; private String username; private String userpwd; private String sex; private String address; private String salt; }
public interface UserDao extends BaseMapper
{ }
开启扫描dao包
public interface UserService { public User findByUsername(String username); }
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public User findByUsername(String username) { // 创建一个查询条件包装器 QueryWrapper
wrapper = new QueryWrapper<>(); // 设置查询条件为"username = username" wrapper.eq("username", username); // 使用查询条件执行查询操作,返回单个用户对象 User user = userDao.selectOne(wrapper); return user; } }
public class MyRealm extends AuthorizingRealm { @Autowired protected UserService userService; // 授权--权限 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 在此处添加授权逻辑 return null; } //认证 -- 登录 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 1. 获取登录账号 String username = token.getPrincipal().toString(); // 2. 根据账号获取用户信息 User user = userService.findByUsername(username); if (user != null) { // 使用用户的盐值创建 ByteSource 对象 ByteSource salt = ByteSource.Util.bytes(user.getSalt()); // 创建 SimpleAuthenticationInfo 对象,包含用户信息、密码、盐值和 Realm 名称 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName()); return info; } // 用户不存在,返回 null return null; } }
@Data public class LoginVo { private String Password; private String Username; }
@Controller public class LoginController { @PostMapping("/login") public String login(LoginVo loginVo) { // 获取当前主体对象 Subject subject = SecurityUtils.getSubject(); // 创建用户名密码令牌 UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUsername(), loginVo.getPassword()); try { // 调用主体的登录方法进行认证 subject.login(token); // 登录成功,返回成功标识 return "success"; } catch (Exception e) { e.printStackTrace(); // 登录失败,重定向到登录页面 return "redirect:/login.html"; } } }
----(相当于ssm中的spring配置文件)
package com.wqg.config; import com.wqg.realm.MyRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.Filter; import java.util.HashMap; import java.util.Map; /** * @ fileName:ShiroConfig * @ description: * @ author:wqg * @ createTime:2023/7/7 16:33 */ @Configuration public class ShiroConfig { @Bean public DefaultWebSecurityManager securityManager() { // 创建默认的 Web 安全管理器 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置安全管理器使用的 Realm securityManager.setRealm(myRealm()); // 返回安全管理器 return securityManager; } @Bean public MyRealm myRealm(){ MyRealm myRealm=new MyRealm(); //设置密码加密器 myRealm.setCredentialsMatcher(credentialsMatcher()); return myRealm; } @Value("${shiro.hashAlgorithmName}") private String hashAlgorithmName; @Value("${shiro.hashIterations}") private int hashIterations; @Bean public HashedCredentialsMatcher credentialsMatcher() { // 创建密码匹配器对象 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); // 设置密码算法名称 credentialsMatcher.setHashAlgorithmName(hashAlgorithmName); // 设置哈希迭代次数 credentialsMatcher.setHashIterations(hashIterations); // 返回密码匹配器对象 return credentialsMatcher; } @Bean(name = "shiroFilter") public ShiroFilterFactoryBean factoryBean() { // 创建 Shiro 过滤器工厂 Bean ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager()); // 设置登录页面的 URL shiroFilterFactoryBean.setLoginUrl("/login.html"); // 设置过滤规则 Map
map = new HashMap<>(); // 指定 /login URL 不需要进行认证 map.put("/login", "anon"); // 其他 URL 需要进行认证 map.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); // 返回 Shiro 过滤器工厂 Bean return shiroFilterFactoryBean; } //springboot如何注册web三大组件。 @Bean public FilterRegistrationBean filterRegistrationBean() { // 创建过滤器注册Bean对象 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); // 设置过滤器为DelegatingFilterProxy filterRegistrationBean.setFilter(new DelegatingFilterProxy()); // 设置过滤器名称 filterRegistrationBean.setName("shiroFilter"); // 添加过滤器的URL模式,匹配所有URL filterRegistrationBean.addUrlPatterns("/*"); // 返回过滤器注册Bean对象 return filterRegistrationBean; } }
登录
Title 登录成功~~~
2.1.修改Realm
@Autowired protected PermissionService permissionService; // 授权--权限 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取主体中的用户对象 User user = (User) principals.getPrimaryPrincipal(); // 根据用户ID查询用户权限列表 List
list = permissionService.selectPermissionByUserid(user.getUserid()); // 如果权限列表不为空 if (list.size() != 0) { // 创建 SimpleAuthorizationInfo 对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 将权限列表添加到授权信息中 info.addStringPermissions(list); // 返回授权信息 return info; } // 返回空,表示无授权信息 return null; } 2.2.创建Service
public interface PermissionService { public List
selectPermissionByUserid(Integer userid); } @Service public class PermissionServiceImpl implements PermissionService { @Autowired private PermissionDao permissionDao; @Override public List
selectPermissionByUserid(Integer userid) { // 根据用户ID查询用户权限列表 List permissionList = permissionDao.findPermissionByUserid(userid); // 使用流操作将权限列表中的每个权限对象映射为权限编码,并收集为新的列表 List collect = permissionList.stream().map(Permission::getPercode).collect(Collectors.toList()); // 返回权限编码列表 return collect; } } 2.3.创建PermissionDao
@Mapper public interface PermissionDao extends BaseMapper
{ List findPermissionByUserid(Integer userid); } 2.4.创建PermissionDao.xml
2.5.创建UserController
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/query") @RequiresPermissions(value = {"user:query","user:delete"},logical = Logical.OR) //可以通过多个路径访问内部资源 //@RequiresPermissions(value = "user:query") public String query(){ return "user:query------------------------"; } @GetMapping("/update") @RequiresPermissions(value = "user:update") public String update(){ return "user:update------------------------"; } @GetMapping("/delete") @RequiresPermissions(value = "user:delete") public String delete(){ return "user:delete------------------------"; } @GetMapping("/insert") @RequiresPermissions(value = "user:insert") public String insert(){ return "user:insert------------------------"; } @GetMapping("/export") @RequiresPermissions(value = "user:export") //该注解不能被识别 public String export(){ return "user:export------------------------"; } }
2.6.修改登录成功页面
Title 登录成功~~~增
删
改
查
2.7.添加依赖
com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 2.8.ShiroConfig修改
/** * 这里是为了能在html页面引用shiro标签, */ @Bean(name = "shiroDialect") public ShiroDialect shiroDialect() { // 创建 Shiro 方言对象,用于在 Thymeleaf 中集成 Shiro 标签 return new ShiroDialect(); }
测试
2.9.权限不足时跳转到一个页面
未跳转:
实现跳转:
创建MyExceptionHandler
@ControllerAdvice @Slf4j public class MyExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String authorizationException(Exception e){ log.error("异常的内容====="+e.getMessage()); return "403" ; } }
创建403.html
Title 权限不足~~~~测试
创建Result
@Data @NoArgsConstructor @AllArgsConstructor public class Result { private Integer code; private String msg; private Object data; }
3.1.登录成功或失败---返回json数据
修改LoginController
测试:
3.2.权限不足时---返回json数据
修改MyExceptionHandler
测试
3.3.未登录时---返回json数据
添加依赖
com.alibaba fastjson 1.2.83 创建LoginFilter
public class LoginFilter extends FormAuthenticationFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //设置响应的内容类型为JSON,并使用UTF-8编码 response.setContentType("application/json;charset=utf-8"); // 获取用于写入响应的PrintWriter对象 PrintWriter writer = response.getWriter(); // 创建一个Result对象,包含401状态码和提示信息 Result result = new Result(401, "请先登录---", null); // 将Result对象转换为JSON字符串 String jsonString = JSON.toJSONString(result); // 将JSON字符串写入响应 writer.println(jsonString); // 刷新并关闭PrintWriter对象 writer.flush(); writer.close(); // 返回false,表示请求应在此处停止 return false; } }
修改ShiroConfig
测试,不登录,直接访问:
引入依赖
org.crazycake shiro-redis 3.3.1 修改 ShiroConfig
测试
引入依赖
io.github.jianzhichun spring-boot-starter-swagger2 0.0.1 com.github.xiaoymin swagger-bootstrap-ui 1.9.6 创建swagger配置文件
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration //swagger配置文件 public class SwaggerConfig { @Bean //加在方法上,表示把方法的返回结果交于spring容器来管理该对象,里面封装了接口文档的信息 public Docket docket() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .groupName("qy165第五组") .apiInfo(getInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.wqg.controller")) .build(); return docket; } private ApiInfo getInfo() { Contact DEFAULT_CONTACT = new Contact("张三", "151******", "319***[email protected]"); ApiInfo apiInfo = new ApiInfo("学生管理系统API文档", "学生管理系统API文档", "2.0", "http://localhost:8080/doc.html", DEFAULT_CONTACT, "游戏公司", "www.4399.com"); return apiInfo; } }
设置放行
测试http://localhost:8080/doc.html