①导入maven 依赖
②配置Shiro的配置文件shiro.ini 以及log4j相关的配置文件
③启动运行,快速开始
Apache Shiro特性
- Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
- Authorization:授权,即验证权限,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限。
- Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境的,也可以是Web环境的。
- Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
- Web Support:Web支持,可以非常容易的集成到Web环境中
- Caching:缓存,比如用户登录后,其用户信息,拥有的角色/权限不必每次去查,提高效率。
- Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
- Testing:提供测试支持
- Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
- Rember Me:记住我,这是非常常见的功能,即一次登录后,下次再来的话不用登录了。
Shiro架构
-
Subject:主体,代表了当前的“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SercurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
-
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,可以把SecurityManager看做是DispatcherServlet前端控制器。
-
Realm:域,Shiro从Realm获取安全数据(如用户,角色,权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源
SpringBoot 整合Shiro
①导入相关依赖shiro-spring等
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
②配置类ShiroConfig
ShiroFilterFacroryBean
DefaultWebSecurityManager
realm 对象 需要自定义
package com.ty.shiro02.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultSecurityManager") DefaultSecurityManager defaultSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultSecurityManager);
return shiroFilterFactoryBean;
}
@Bean
public DefaultSecurityManager defaultSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(userRealm);
return defaultSecurityManager;
}
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
package com.ty.shiro02.config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权....");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证....");
return null;
}
}
③shiro 实现登录拦截
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> maps=new LinkedHashMap<>();
maps.put("/add","authc");
maps.put("/update","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);
//在配置类中设置的路径无效,必须在controller里设置
shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
return shiroFilterFactoryBean;
}
④Shiro 实现用户认证
package com.ty.shiro02.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/user/add")
public String add(){
return "add";
}
@RequestMapping("/user/update")
public String update(){
return "update";
}
@RequestMapping({"/index","/"})
public String toIndex(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/loginCheck")
public String loginCheck(String username, String password, Model model){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);
return "/index";
} catch (UnknownAccountException uae) {
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException ice) {
model.addAttribute("msg","密码错误");
return "login";
}
}
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证....");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username="ty";
String password="tyty123";
if (!username.equals(usernamePasswordToken.getUsername())){
return null;
}
return new SimpleAuthenticationInfo("",password,"");
}
⑤Shiro 整合mybatis
引入相关依赖,
配置相关属性,编写实体类,接口UserMapper
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证....");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
User user = userService.selectUserByName(usernamePasswordToken.getUsername());
if(user==null){
return null;
}
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
⑥Shiro 请求授权访问
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权....");
Subject subject = SecurityUtils.getSubject();
User principal = (User) subject.getPrincipal();
SimpleAuthorizationInfo info= new SimpleAuthorizationInfo();
info.addStringPermission(principal.getRole());
return info;
}
@Configuration
public class MyShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> maps=new LinkedHashMap<>();
maps.put("/user/add","perms[user:add]");
maps.put("/user/update","perms[user:update]");
maps.put("/user/**","authc");
maps.put("/index","authc");
maps.put("/","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);
//在配置类中设置的路径无效,必须在controller里设置
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthor");
return shiroFilterFactoryBean;
}
⑦Thymeleaf 整合shiro
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
注册组件ShiroDialect
引入约束
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>