从网上搜索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. vs2010编译C++ 静态成员函数的引用

    // CTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using names ...

  2. 微信小程序-发送模板消息

    1 添加一个小程序的消息模板,获取到模板id,存储到数据库中,方便以后修改调用 2. https://developers.weixin.qq.com/miniprogram/dev/api-back ...

  3. java#内部类和嵌套类

    内容思路来自Java编程思想,个人读书做的笔记,仅个人复习之用,故他人参考请自行辨别内容是否有错误. 在类的类部可以定义类,叫做内部类.如果这个内部类被static修饰,此时内部的类叫做嵌套类. 内部 ...

  4. Ceph 概念理解

    简介 Ceph是一个可靠地.自动重均衡.自动恢复的分布式存储系统,根据场景划分可以将Ceph分为三大块,分别是对象存储.块设备存储和文件系统服务. 在虚拟化领域里,比较常用到的是Ceph的块设备存储, ...

  5. servlet3.0的文件上传代码配置怎么写

    之前学习过xml配置servlet3.0的文件上传,但是变成code方式一直不知道怎么弄,相比较起来apache的文件上传配置和xml倒是没什么太大区别. 直接上代码:无需依赖,只要一个方法就好了cu ...

  6. 2020/2/21 fiyocms代码审计

    0x00 前言 上午上了网课,一上午就装好了cms,下午还有网课,要是结束的早就进行审计. 解决了一下phpstudy使用过程中: Forbidden You don't have permissio ...

  7. 4 —— node —— 启动一个 http 服务器

    const http = require('http'); const server = http.createServer(); // 绑定客户端请求事件 // on => 绑定事件 // r ...

  8. jenkins 最新版 搭建

    jenkins 中文网:https://jenkins.io/zh/ 点击下载:https://jenkins.io/zh/download/ 然后选择对应的安装环境,我的CentOS 7.6: 有外 ...

  9. ssh-keygen 签名ca证书

    介绍 ssh-keygen命令用于为"ssh" 生成,管理和转换认证秘钥,支持RSA和DSA两种认证秘钥 生成秘钥对 ssh-keygen -b 2048 -C milo -f 2 ...

  10. Linux重要命令练习之bc