简介:这一节主要是集成shiro进行鉴权, 用户登录/退出

环境:

IDEA15+
JDK1.8+
Maven3+

代码:

https://git.oschina.net/xinshu/springboot-shiro

一、shiro 基本功能

http://shiro.apache.org/

Authentication:身份认证,验证用户身份;

Authorization:授权,验证某个已认证的用户是否拥有某个权限;如:验证某个用户是否拥有某个角色。或者验证某个用户对某资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

二、shiro 流程及基本概念

Shiro的对外API核心就是Subject;

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm:Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
 
一个简单的Shiro应用:
1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
2、需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

三、shiro Authentication认证特点

Authentication is the process of identity verification– you are trying to verify a user is who they say they are. To do so, a user needs to provide some sort of proof of identity that your system understands and trusts.

The Shiro framework is designed to make authentication as clean and intuitive as possible while providing a rich set of features. Below is a highlight of the Shiro authentication features.

Subject Based - Almost everything you do in Shiro is based on the currently executing user, called a Subject. And you can easily retrieve the Subject anywhere in your code. This makes it easier for you to understand and work with Shiro in your applications.

Single Method call - The authentication process is a single method call. Needing only one method call keeps the API simple and your application code clean, saving you time and effort.

Rich Exception Hierarchy - Shiro offers a rich exception hierarchy to offered detailed explanations for why a login failed. The hierarchy can help you more easily diagnose code bugs or customer services issues related to authentication. In addition, the richness can help you create more complex authentication functionality if needed.

‘Remember Me’ built in - Standard in the Shiro API is the ability to remember your users if they return to your application. You can offer a better user experience to your them with minimal development effort.

Pluggable data sources - Shiro uses pluggable data access objects (DAOs), called Realms, to connect to security data sources like LDAP and Active Directory. To help you avoid building and maintaining integrations yourself, Shiro provides out-of-the-box realms for popular data sources like LDAP, Active Directory, and JDBC. If needed, you can also create your own realms to support specific functionality not included in the basic realms.

Login with one or more realms - Using Shiro, you can easily authenticate a user against one or more realms and return one unified view of their identity. In addition, you can customize the authentication process with Shiro’s notion of an authentication strategy. The strategies can be setup in configuration files so changes don’t require source code modifications– reducing complexity and maintenance effort.

四、依赖资源

与上一节相比,这里主要依赖shiro-spring构建,由于shiro-spring构建又依赖于shiro-core及shiro-web控件,所以pom.xml文件只需依赖shiro-spring即可

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>

五、配置及实现

从Shiro工作流程中,我们需要配置SecurityManager(负责接收Subject校验请求、与其他组件交互)及Reaml(获取安全数据信息)。由于是用spring-boot, 这里推荐由配置传统的xml文件改为java 注解@Configuration方式配置,主要配置如下:

@Configuration
public class ShiroConfiguration { private static Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); @Bean(name = "ShiroRealmImpl")
public ShiroRealmImpl getShiroRealm() {
return new ShiroRealmImpl();
} @Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(getShiroRealm());
return defaultWebSecurityManager;
} @Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} @Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean() { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager()); shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/welcome");
filterChainDefinitionMap.put("/welcome", "authc");
filterChainDefinitionMap.put("/**", "anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}

其中:

Spring中使用shiro时, Spring容器会根据bean名称查找shiroFilter的bean,同时将所有Filter操作委托给它,shiroFilter作为入口定义了需要控制的URL规则类型,然后根据URL规则进行相应的安全控制,具体shiroFilter定义过程如下:

1.Spring中定义了一类特殊的Bean——FactoryBean,当需要“shiroFilter”的bean时, 会调用ShiroFilterFactoryBean的getObject()方法来实现

很显然ShiroFilterFactoryBean定义过程中需要指定Securitymanager, successUrl, loginUrl以及filterChainDefinitionMap等。

2.定义securityManager bean, 指定securitymanager类型,同时设置安全数据的获取方式setRealm(Realm realm)

3.定义Realm的bean,ShiroRealmImpl类具体实现如下:
public class ShiroRealmImpl extends AuthenticatingRealm {

    private static Logger logger = LoggerFactory.getLogger(ShiroRealmImpl.class);

    @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = usernamePasswordToken.getUsername();
String encodedPassword = new Sha256Hash(usernamePasswordToken.getPassword()).toBase64(); logger.info("------------------------authentication--------------------------"); if (false) {
// TODO 用户名不存在
throw new UnknownAccountException(); } else if (false) {
// TODO 密码错误
throw new IncorrectCredentialsException();
} return new SimpleAuthenticationInfo(new ShiroUser(username, "用户编码", "用户名称"),
String.valueOf(usernamePasswordToken.getPassword()),
ByteSource.Util.bytes("用户id"), getName());
}
}
主要是实现了doGetAuthenticationInfo(AuthenticationToken token)方法,来验证当前用户身份信息
4.另外值得说明的是这里定义了,lifecycleBeanPostProcessor Bean这里主要的目的是管理shiro的生命周期
5.Spring mvc 登录/退出Controller, 
请求/login时, http谓语为GET类型则加载login.jsp页面,POST类型作为验证用户身份的请求,调用subject.login(usernamePasswordToken)成功重定向到welcome.jsp, 否则重定向到login.jsp页面
@Controller
public class LoginController {
private static Logger logger = LoggerFactory.getLogger(LoginController.class); @Value(value = "${application.message}")
private String message; @RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginInit(Map<String, Object> model) {
return "login";
} @RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(Map<String, Object> model, @RequestParam("userid") String userId,
@RequestParam("password") String password) { UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userId, password); Subject subject = SecurityUtils.getSubject();
try {
subject.login(usernamePasswordToken);
} catch (UnknownAccountException uae) {
logger.info("未知账户");
} catch (IncorrectCredentialsException ice) {
logger.info("密码不正确");
} catch (LockedAccountException lae) {
logger.info("账户已锁定");
} catch (ExcessiveAttemptsException eae) {
logger.info("用户名密码次数过多");
} catch (AuthenticationException ae) {
logger.info("用户名密码不正确");
} if (subject.isAuthenticated()) {
logger.info("登录认证通过");
model.put("time", new Date());
model.put("message", this.message);
return "redirect:/welcome";
} else {
usernamePasswordToken.clear();
return "redirct:/login";
}
} @RequestMapping(value="/logout", method=RequestMethod.POST)
public String logout(){
SecurityUtils.getSubject().logout();
return "redirect:/login";
}
}
 
 
 
 

springboot-shiro chapter03 login的更多相关文章

  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 + mysql + mybatis 工程快速搭建

    1. 新建 springboot 工程 2. 随便起个名字 3. 初始化工程 4. 导入 shiro 和 thymeleaf 依赖 <!-- thymeleaf依赖 --> <dep ...

随机推荐

  1. Redis安全性配置

    最近Redis刚爆出一个安全性漏洞,我的服务器就“光荣的”中招了.黑客攻击的基本方法是: 扫描Redis端口,直接登录没有访问控制的Redis 修改Redis存盘配置:config set dir / ...

  2. JAVA多线程------用1

    火车上车厢的卫生间,为了简单,这里只模拟一个卫生间,这个卫生间会被多个人同时使用,在实际使用时,当一个人进入卫生间时则会把卫生间锁上,等出来时 打开门,下一个人进去把门锁上,如果有一个人在卫生间内部则 ...

  3. 二次剩余-Cipolla

    二次剩余 \(Cipolla\) 算法 概述 大概就是在模 \(p\) 意义下开根号,如求解方程\(x^2\equiv n(mod\ p)\). 这里只考虑 \(p\) 为素数的情况.若 \(p=2\ ...

  4. UWP 中的 LaunchUriAsync,使用默认浏览器或其他应用打开链接

    古老的 Win32 应用启动其他程序太过方便,以至于一部分开发者都已经不记得 Windows 能通过关联协议的方式通过统一资源定位符(URI)来启动应用程序了. 转到 UWP 后,使用 URI 启动应 ...

  5. python笔记-10(socket提升、paramiko、线程、进程、协程、同步IO、异步IO)

    一.socket提升 1.熟悉socket.socket()中的省略部分 socket.socket(AF.INET,socket.SOCK_STREAM) 2.send与recv发送大文件时对于黏包 ...

  6. 2018HN省队集训

    HNOI2018省队集训 Day 1 流水账 T1 tree 换根+求\(lca\)+求子树和,一脸bzoj3083遥远的国度的既视感.子树和讨论一下就好了,\(lca\)?也是大力讨论一波. 先写了 ...

  7. matplotlib ----- 初步

    直接看几段代码即可: # 加载模块的方式 import matplotlib.pyplot as plt import numpy as np # 最简单的单线图 x = np.linspace(0, ...

  8. distinct和group by的性能比较

    distinct和group by的性能比较 当去重复的字段 的个数比较多的时候,group by 比distinct要快很多 当去重复的字符 的个数比较少的时候,distinct 比group by ...

  9. Google Chrome 调试JS简单教程[更新]

    题外话,刚开始我写这篇内容只是将自己了解的一些知识放上来,不巧的是我分析了我的来访日志,很多朋友都有这个需求,为了大家没有白来,我决定充实下这篇文章.最近更新时间2014-02-14 chrome版本 ...

  10. 利用 netsh 给 mysql 开启多端口监听

    利用 netsh 给 mysql 开启多端口监听 标题党,实际并不是真的多端口监听,只是端口转发而已. 由于某种特殊原因需要 mysql 服务器多个端口监听. mysql 服务器本身是不支持的,但可以 ...