技术标签: spring boot java restful shiro java学习笔记
最近做的项目整合了SpringBoot+Shiro,自己也不会,就就在网上现学现用,然后发现也有一篇满足的我需要的一篇完整帖子,所以有了这篇。废话少说。
还是先上一张图,大概了解一下shiro框架,有理论有实践。
对上图简单的进行说明
三个核心组件:Subject, SecurityManager 和 Realms.
Subject: 即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager: 它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
话不多说 撸代码
我的项目目录结构
导入shiro关键依赖
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.2</version>
</dependency>
<!-- shiro ehcache 缓存-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.9</version>
</dependency>
自定义Realm
package com.xiang.springboot_shiro.config.shiro;
import com.xiang.springboot_shiro.entity.model.User;
import com.xiang.springboot_shiro.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class CustomerRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String principal = token.getPrincipal().toString();
User user = userService.selectUserByName(principal);
if (user == null){
return null;
}else {
String username = user.getUsername();
String password = user.getPassword();
//2、用户名。 2、密码 3、realm,即当前realm的名称
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,getName());
return info;
}
}
}
shiroConfig
package com.xiang.springboot_shiro.config.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class shiroConfig {
/**
* 过滤器
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
map.put("/login","anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
/**
* 安全管理器
* @param customerRealm
* @return
*/
@Bean
public SessionsSecurityManager securityManager(CustomerRealm customerRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置自定义Realm
securityManager.setRealm(customerRealm);
return securityManager;
}
/**
* 自定义Realm
* @return
*/
@Bean
CustomerRealm customerRealm(){
CustomerRealm customerRealm = new CustomerRealm();
//凭证匹配器
customerRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customerRealm;
}
/**
* 凭证匹配器
* 若密码使用MD5加密后,一定设置密码匹配策略
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
}
controller
package com.xiang.springboot_shiro.controller;
import cn.hutool.core.util.StrUtil;
import com.xiang.springboot_shiro.entity.model.User;
import com.xiang.springboot_shiro.service.UserService;
import com.xiang.springboot_shiro.utils.RestMessage;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sun.security.util.Password;
import sun.text.normalizer.UBiDiProps;
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/login")
public RestMessage login(String username,String password){
//引入了hutool工具类
if (StrUtil.isBlank(username)){
return RestMessage.newInstance(false,"用户名不能为空",null);
}
if (StrUtil.isBlank(password)){
return RestMessage.newInstance(false,"密码不能为空",null);
}
//用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
//shiro登录接口,这里建议自己调试看一下,会进入我们自定义的realm的AuthenticationInfo
subject.login(token);
} catch (UnknownAccountException e) {
return RestMessage.newInstance(false,"用户名错误",null);
}catch (IncorrectCredentialsException e){
return RestMessage.newInstance(false,"密码错误",null);
}catch (AuthenticationException e){
return RestMessage.newInstance(false,"没有权限",null);
}
return RestMessage.newInstance(true,"登录成功",null);
}
}
测试结果
赠送一个消息返回工具类
package com.xiang.springboot_shiro.utils;
import java.io.IOException;
import java.io.Serializable;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* 接口返回消息
* @author xiang
*
*/
//@ApiModel(description= "返回响应数据")
public class RestMessage<T> implements Message,Serializable{
private static final long serialVersionUID = -1865510446859810360L;
//@ApiModelProperty(value = "是否成功")
private boolean success;
//@ApiModelProperty(value = "消息对象")
private String message;
//@ApiModelProperty(value = "消息代码")
private String code;
//@ApiModelProperty(value = "返回对象")
private T data;
public RestMessage(){
}
public static <T> RestMessage<T> newInstance(boolean success,String message,T data){
return new RestMessage<T>(success,message,data);
}
public static <T> RestMessage<T> newInstance(boolean success,String code,String message,T data){
return new RestMessage<T>(success,code,message,data);
}
public RestMessage(boolean success,String message,T data){
this.success = success;
this.message = message;
this.data = data;
this.code="200";
}
public RestMessage(boolean success,String code,String message,T data){
this.success = success;
this.message = message;
this.data = data;
this.code=code;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toJsonString() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public static <S> RestMessage<S> parseJsonString(String jsonstr,TypeReference<RestMessage<S>> typeReference) throws IOException{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
RestMessage<S> rest = mapper.readValue(jsonstr, typeReference);
return rest;
}
public static void main(String[] args) throws IOException {
//String jsonstr = "{\"success\":true,\"message\":\"查询成功\",\"data\": [{\"id\": 50,\"number\":\"001\",\"name\": \"苹果\",\"price\": 12},{\"id\": 50,\"number\":\"001\",\"name\": \"苹果\",\"price\": 12}]}";
//String jsonstr = "{\"success\":true,\"message\":\"查询成功\",\"data\": {\"id\": 50,\"number\":\"001\",\"name\": \"苹果\",\"price\": 12}}";
//String jsonstr = "{\"success\":true,\"message\":\"查询成功\",\"data\": 123}";
//RestMessage<List<Product>> rest= RestMessage.parseJsonString(jsonstr,new TypeReference<RestMessage<List<Product>>>(){});
//List<Product> list = rest.getData();
//System.out.println(list.get(0).getName());
}
}
package com.xiang.springboot_shiro.utils;
public interface Message {
String toJsonString();
}
文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大
文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码
文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版
文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗
文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程
文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0
文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader
文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型
文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写
文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录
文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点
文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文