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 ...
随机推荐
- 51nod 1099:任务执行顺序 贪心
1099 任务执行顺序 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 取消关注 有N个任务需要执行,第i个任务计算时占R[i]个空间,而后会释放一部分, ...
- HiBench成长笔记——(10) 分析源码execute_with_log.py
#!/usr/bin/env python2 # Licensed to the Apache Software Foundation (ASF) under one or more # contri ...
- PHP代码审计之入门实战
系统介绍 CMS名称:新秀企业网站系统PHP版 官网:www.sinsiu.com 版本:这里国光用的1.0 正式版 (官网最新的版本有毒,网站安装的时候居然默认使用远程数据库???迷之操作 那站长的 ...
- 刷题21. Merge Two Sorted Lists
一.题目说明 这个题目是21. Merge Two Sorted Lists,归并2个已排序的列表.难度是Easy! 二.我的解答 既然是简单的题目,应该一次搞定.确实1次就搞定了,但是性能太差: R ...
- mysql日常小总结(其实就今天)
联表查询: SELECT t1.user_Name FROM t_user AS t1 , t_comment AS t2 WHERE t2.user_id=t1.id 结果如图: 加上GRO ...
- 0101-ioc
背景 ioc是spring的基础,即控制反转.springboot基于注解使用ioc. ioc spring称所有被管理的对象为bean, spring ioc主要通过描述的方式完成3类bean的管理 ...
- manjaro更换深度桌面 卸载ked桌面
下载需要的桌面环境 pacman -S deepin deepin-extra 修改/etc/lightdm/lightdm.conf sudo nano /etc/lightdm/lightdm.c ...
- Job for nginx.service failed because the control process exited with error code. See “systemctl stat
启动nginx服务时如果遇到这个错误 Job for nginx.service failed because the control process exited with error code. ...
- (八)微信小程序---获取定位信息chooseLocation
微信小程序---获取定位信息 chooseLocation wxml <view bindtap="getlocalPath">{{localPath}}</v ...
- 配置thinkphp对mysql线上线下切换不同环境的配置 - (mysql-thinkphp) (1)
1.先打印出配置项的信息,在Index控制器下面的index->index里面设置 namespace app\index\controller; class Index { public fu ...