shiro笔记
什么是Shiro?
Apache Shiro 是一个Java 的安全(权限)框架。 Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环 境。 Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
Authentication:身份认证、登录,验证用户是不是拥有相应的身份;
Authorization:授权权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否
进行什么操作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限!
Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境,也可以是Web环境;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储;
Web Support:Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高效率
Concurrency:Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
subject:对外api核心是Subject,表示当前用户。其与SecurityManager进行交互。SecurityManager才是执行者。
SecurityManager:安全管理器。所有安全操作都跟其有关。并且管理所有的subject。
Realm:Shiro从Realm获取安全数据(如用户,角色,权限)就是说SecurityManager 要验证用户身份,那么它需要从Realm 获取相应的用户进行比较,来确定用户的身份是否合法;也需要从Realm得到用户相应的角色、权限,进行验证用户的操作是否能够进行,可以把Realm看成DataSource;
Subject:任何可以与应用交互的 ‘用户’;
Security Manager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏,所有具体的交互都通过Security Manager进行控制,它管理者所有的Subject,且负责进行认证,授权,会话,及缓存的管理。
Authenticator:负责Subject认证,是一个扩展点,可以自定义实现;可以使用认证策略
(Authentication Strategy),即什么情况下算用户认证通过了;
Authorizer:授权器,即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的那些功能;
Realm:可以有一个或者多个的realm,可以认为是安全实体数据源,即用于获取安全实体的,一般在应用中都需要实现自己的realm
SessionManager:管理Session生命周期的组件
CacheManager:缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能;
Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于密码加密,解密等
整合shiro
1. Subject:用户主体
2. SecurityManager:安全管理器
3. Realm:Shiro 连接数据
1.写Shiro 配置类 config包
注:UserRealm==>DefaultWebSecurityManager==> ShiroFilterFactoryBean
他们的依赖关系@bean依次注入。
package polo.shiro.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
//添加shiro的内置过滤器
/*
anno:无需认证可以访问
authc:必须认证才可访问
user:必须拥有 记住我 功能才能用
perms:拥有对某个资源的权限才能访问
roles:拥有某个角色权限才能访问
*/
//拦截
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add", "perms[user:add]");//授权 未授权跳转到未授权页面 perms
filterMap.put("/user/update", "perms[user:update]");//授权 未授权跳转到未授权页面 perms
filterMap.put("/user/*", "authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
//未授权页面请求
bean.setUnauthorizedUrl("/oauth");
return bean;
}
//DfaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象
@Bean(name = "userRealm")
public UserRealm userRealm() {
return new UserRealm();
}
//整Σshiro方言
@Bean
public ShiroDialect getShiroDialect() {
return new ShiroDialect();
}
}
登录认证操作
编写一个登录的controller
package polo.shiro.controller;
import org.apache.catalina.security.SecurityUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@RequestMapping({"/", "/index"})
public String toIndex(Model model) {
model.addAttribute("msg", "hello,Shiro");
return "index";
}
@RequestMapping("/user/add")
public String add() {
return "user/add";
}
@RequestMapping("/user/update")
public String update() {
return "user/update";
}
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
@RequestMapping("/login")
public String login(String username, String password, Model model) {
//获取用户数据
Subject subject = SecurityUtils.getSubject();
//加密封装登录用户
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
//执行登录方法
subject.login(token);
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用户名错误");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/oauth")
@ResponseBody
public String unauthorized() {
return "未经授权无法访问此页面";
}
}
在 UserRealm 中编写用户认证的判断逻辑
package polo.shiro.config;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import polo.shiro.pojo.User;
import polo.shiro.service.UserService;
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//拿到当前用户的登录对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();
//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());
//去数据库拿信息
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
//获取当前用户
User user = userService.queryUserByName(usernamePasswordToken.getUsername());
if (user == null) {
return null;
}
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser", user);
//可以加密 MD5
return new SimpleAuthenticationInfo(user, user.getPwd(), "");
}
}
rrentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute(“loginUser”, user);
//可以加密 MD5
return new SimpleAuthenticationInfo(user, user.getPwd(), "");
}
}