SpringBoot+Shiro (一)
从网上搜索SpringBoot+Shiro相关文章,大部分都需要DB和Ecache的支持。这里提供一个最简单的Spring+Shiro的配置。
前言:
1. 由于SpringBoot官方已经不再建议使用jsp,并且前后端分离及服务化的大趋势也越来越强烈,所以本文旨在搭建一个Restfull的web服务。
2. Rest接口的授权基于Shiro注解的方式实现,这样更灵活更容易掌控。
pom依赖:
这是最小化的依赖项,缺一不可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
创建一个Realm
这里面用户认证和授权没有通过连接DB的方式实现,用户信息(用户名、密码)以及用户权限直接硬编码到了代码里。从代码可看出这个例子只支持两个用户:admin/admin、guest/guest,且admin用户拥有角色admin和权限permission1、permission2,guest用户拥有角色guest和权限permission3、permission4.
public class PropertiesRealm extends AuthorizingRealm {
// 用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (authenticationToken instanceof UsernamePasswordToken) {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
String password = new String(token.getPassword());
if ((username.equals("admin") && password.equals("admin")) ||
(username.equals("guest") && password.equals("guest"))) {
return new SimpleAuthenticationInfo(username, password, getName());
} else {
throw new AuthenticationException("用户名或密码错误");
}
} else if (authenticationToken instanceof RememberMeAuthenticationToken) {
RememberMeAuthenticationToken token = (RememberMeAuthenticationToken) authenticationToken;
// TODO: 2018/10/24
return null;
} else if (authenticationToken instanceof HostAuthenticationToken) {
HostAuthenticationToken token = (HostAuthenticationToken) authenticationToken;
// TODO: 2018/10/24
return null;
} else {
throw new AuthenticationException("未知的AuthenticationToken类型");
}
}
// 用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
if (username.equals("admin")) {
simpleAuthorizationInfo.addRole("admin");
simpleAuthorizationInfo.addStringPermission("permission1");
simpleAuthorizationInfo.addStringPermission("permission2");
} else if (username.equals("guest")) {
simpleAuthorizationInfo.addRole("guest");
simpleAuthorizationInfo.addStringPermission("permission3");
simpleAuthorizationInfo.addStringPermission("permission4");
}
return simpleAuthorizationInfo;
}
}
创建SpringBootApplication
下面这段代码中,需要注意的就是ShiroFilterFactoryBean和SimpleMappingExceptionResolver这两个bean:
1. SimpleMappingExceptionResolver:Shiro通过注解的方式校验用户认证和授权时,如果用户未认证或权限不足,Shiro不会进行页面跳转,而是直接抛出异常。所以我们需要定义SimpleMappingExceptionResolver来处理这两个异常,以保证我们的rest接口在用户未认证或权限不足的时候返回正确的json数据。
2. ShiroFilterFactoryBean:这个bean不需要setSuccessUrl()、setLoginUrl()和setUnauthorizedUrl()。因为Shiro通过注解的方式校验用户认证和授权时,如果用户未认证或权限不足,Shiro不会进行页面跳转,而是直接抛出异常,所以setLoginUrl()和setUnauthorizedUrl()就不需要了。由于我们是做Rest接口服务,那么用户认证过程中也是调用Rest API校验用户身份,校验通过后由前端页面路由至登录成功页面,所以setSuccessUrl()也不需要了。
@SpringBootApplication
public class ShiroApplication { public static void main(String[] args) {
SpringApplication.run(ShiroApplication.class);
} @Bean
public PropertiesRealm propertiesRealm() {
return new PropertiesRealm();
} @Bean
public SecurityManager securityManager(PropertiesRealm propertiesRealm) {
return new DefaultWebSecurityManager(propertiesRealm);
} @Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
} @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
} @Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
Properties properties = new Properties();
properties.put(UnauthenticatedException.class.getName(), "/unauthenticated");
properties.put(UnauthorizedException.class.getName(), "/unauthorized"); SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
simpleMappingExceptionResolver.setExceptionMappings(properties);
return simpleMappingExceptionResolver;
} }
创建统一的Restfull返回结果包装:
public class Result {
private int code = 200;
private String message = "success";
private Object data;
public Result() {
}
public Result(int code, String message) {
this.code = code;
this.message = message;
}
public Result(Object data) {
this.data = data;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
}
创建Controler
方法说明:
- unauthenticated:根据SimpleMappingExceptionResolver的配置,如果Shiro检测方法请求需要用户登录,则会重定向到/unauthenticated,返回401“需要登录”,以便前端根据状态码做相应的路由跳转。
- unauthorized:根据SimpleMappingExceptionResolver的配置,如果Shiro检测到用户权限不足,则会重定向到/unauthorized,返回401“未授权”,以便前端根据状态码做相应的路由跳转。
- login:用户登录
- logout:用户登出
- getData1、getData2:用来做测试用。getData1需要用户认证,用户完成认证后即可访问;getData2需要用户拥有“admin”角色才能访问。
@RestController
public class LoginController { @GetMapping("unauthenticated")
public Result unauthenticated() {
return new Result(401, "需要登录");
} @GetMapping("unauthorized")
public Result unauthorized() {
return new Result(401, "未授权");
} @PostMapping("login")
public Result login(String username, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
return new Result();
} @PostMapping("logout")
public Result logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return new Result();
} @GetMapping("getData1")
@RequiresUser
public Result getData1() {
return new Result("this is data1");
} @GetMapping("getData2")
@RequiresRoles("admin")
public Result getData2() {
return new Result("this is data2");
}
}
SpringBoot+Shiro (一)的更多相关文章
- springboot + shiro + cas4.2.7 实战
1. 下载地址 https://github.com/apereo/cas/archive/v4.2.7.zip 2. 解压后, 用intellj idea 打开 3. 执行 gradle build ...
- springboot+shiro
作者:纯洁的微笑 出处:http://www.ityouknow.com/ 这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公 ...
- SpringBoot+Shiro+Redis共享Session入门小栗子
在单机版的Springboot+Shiro的基础上,这次实现共享Session. 这里没有自己写RedisManager.SessionDAO.用的 crazycake 写的开源插件 pom.xml ...
- SpringBoot+Shiro入门小栗子
写一个不花里胡哨的纯粹的Springboot+Shiro的入门小栗子 效果如图: 首页:有登录注册 先注册一个,然后登陆 登录,成功自动跳转到home页 home页:通过认证之后才可以进 代码部分: ...
- springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)
相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...
- Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...
- springboot+shiro+redis(集群redis版)整合教程
相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...
- springboot+shiro+redis(单机redis版)整合教程
相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+shiro+redis(单机red ...
- springboot+shiro整合教程
进阶教程: 1. springboot+shiro+redis(单机redis版)整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+s ...
- springboot shiro没有注解解决方案
颓废的悠然 springboot shiro开启注释 shiroconfiguration中增加 1 2 3 4 5 6 7 @Bean public AuthorizationAttri ...
随机推荐
- markdown超链接怎么写?
效果:我的微博 #上面的效果就是下面这种写法: [ 我的微博 ]( http://weibo.com/5833683560/profile?topnav=1&wvr=6&is_all= ...
- SpringBoot学习(学习过程记录)
关于微服务和SOA 这,仅是我学习过程中记录的笔记.确定了一个待研究的主题,对这个主题进行全方面的剖析.笔记是用来方便我回顾与学习的,欢迎大家与我进行交流沟通,共同成长.不止是技术. 官网教程学习ht ...
- windows电脑安装python教程
1 版本选择 2.x版本将慢慢退出历史的舞台,建议你从3.x开始学习,本教程所使用的python版本是3.6 2 下载安装包 进入官网下载页面 https://www.python.org/downl ...
- 二进制枚举之被RE完虐的我的一天
记录一道学长们说有点难度的题目 好好玩啊这道题 ACM程序设计大赛是大学级别最高的脑力竞赛,素来被冠以"程序设计的奥林匹克"的尊称.大赛至今已有近40年的历史,是世界范围内历史最悠 ...
- maven详解 之仓库
Maven仓库分类 MAVEN仓库分类 Maven仓库分为:本地仓库+远程仓库两大类 远程仓库又分为:中央仓库+私服+其它公共远程仓库 1,在Maven中,任何一个依赖.插件或者项目构建的输出,都 ...
- python中的魔术属性与魔法方法
1.魔法属性 · 1.1__doc__魔法属性 表示类的描述信息 class Fo: """ 这是今天第一个魔术属性__doc__""" ...
- jmeter简单压测、下载文件
一.jmeter做简单压测(单机) 1.添加需要压测的HTTP请求 2.添加聚合报告 3.设置压测场景 4.查看聚合报告 二.多机同时进行压测 1.在需要连接的电脑上打开jmeter bin目录下的 ...
- linux下anaconda的安装和使用
1.将python3设置为默认 直接执行这两个命令即可: sudo update-alternatives --install /usr/bin/python python /usr/bin/pyth ...
- 聚类之K均值聚类和EM算法
这篇博客整理K均值聚类的内容,包括: 1.K均值聚类的原理: 2.初始类中心的选择和类别数K的确定: 3.K均值聚类和EM算法.高斯混合模型的关系. 一.K均值聚类的原理 K均值聚类(K-means) ...
- JavaScript 对象所有API解析【2020版】
JavaScript 对象所有API解析[2020版] 写于 2019年08月20日,虽然是2019年写的文章,但现在2020年依旧不过时,现在补充了2019年新增的ES10 Object.fromE ...