从网上搜索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 (一)的更多相关文章

  1. springboot + shiro + cas4.2.7 实战

    1. 下载地址 https://github.com/apereo/cas/archive/v4.2.7.zip 2. 解压后, 用intellj idea 打开 3. 执行 gradle build ...

  2. springboot+shiro

    作者:纯洁的微笑 出处:http://www.ityouknow.com/ 这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公 ...

  3. SpringBoot+Shiro+Redis共享Session入门小栗子

    在单机版的Springboot+Shiro的基础上,这次实现共享Session. 这里没有自己写RedisManager.SessionDAO.用的 crazycake 写的开源插件 pom.xml ...

  4. SpringBoot+Shiro入门小栗子

    写一个不花里胡哨的纯粹的Springboot+Shiro的入门小栗子 效果如图: 首页:有登录注册 先注册一个,然后登陆 登录,成功自动跳转到home页 home页:通过认证之后才可以进 代码部分: ...

  5. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  6. Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...

  7. springboot+shiro+redis(集群redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...

  8. springboot+shiro+redis(单机redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+shiro+redis(单机red ...

  9. springboot+shiro整合教程

    进阶教程: 1. springboot+shiro+redis(单机redis版)整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+s ...

  10. springboot shiro没有注解解决方案

    颓废的悠然   springboot shiro开启注释 shiroconfiguration中增加 1 2 3 4 5 6 7 @Bean     public AuthorizationAttri ...

随机推荐

  1. 7.11 如何应用Varnish

    动态数据缓存 Step 1 修改devault.vcl文件 # This ) # man page for details on VCL syntax and semantics. # # Defau ...

  2. 调用dos

    两个方法 function RunDosCommand(Command: string): string; var hReadPipe: THandle; hWritePipe: THandle; S ...

  3. 在 linux 中遇到 OSError: inotify watch limit reached 错误

    检查系统当前限制,默认应该是 8192: cat /proc/sys/fs/inotify/max_user_watches 可根据需要调整系统限制,但是目前还不知道如何查看每个进程对 watch 的 ...

  4. javacv 通过rtsp 获取视频流 设置帧率

    原文章:https://blog.csdn.net/eguid_1/article/details/52680802 原代码: /** * 按帧录制视频 * * @param inputFile-该地 ...

  5. JSP编码规范

    JSP包含文件 <%@ include file=”relativeURI”%> //在翻译阶段执行加载,比如:校验是否登录通过 jsp的include指令元素读入指定页面的内容.并把这些 ...

  6. 3-Java逻辑控制语句

    目录 Java选择结构 Java循环结构 return.break.continue Math.random()的使用和条件运算符 1.Java选择结构 1.1.if(布尔表达式)单选结构 - 当布尔 ...

  7. 004、mysql使用SHOW语句找出服务器上当前存在什么数据库

    SHOW DATABASES; 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码打赏任意金额给作者(微信号:382477247)哦,谢谢.

  8. Swift 元组 Tuple

    let infoArray:[Any] = ["jack",18,1.88] let infoName=infoArray[0] as!String //此处为Any类型强转为St ...

  9. Java 逆序打印链表

    递归 package cookie; public class PrintListReversal { public void reversalOut(Node head) { if (head != ...

  10. goroutine简介

    一.goroutine简介 Golang中最迷人的一个优点就是从语言层面就支持并发 在Golang中的goroutine(协程)类似于其他语言的线程 并发和并行 并行(parallelism)指不同的 ...