shiro
Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。

可以看到:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject;其每个 API 的含义:
Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
Realm:域,Shiro 从从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
也就是说对于我们而言,最简单的一个 Shiro 应用:
- 应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;
- 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。
从以上也可以看出,Shiro 不提供维护用户 / 权限,而是通过 Realm 让开发人员自己注入。(来源:w3cschool)
导入相关依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency>
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
|
自定义Realm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class UserRealm extends AuthorizingRealm {
@Autowired private UserServiceImpl 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 authenticationToken) throws AuthenticationException {
System.out.println("执行了=》认证doGetAuthenticationInfo方法");
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken; User user = userService.queryByName(userToken.getUsername());
if (user == null){ return null; }
return new SimpleAuthenticationInfo(user,user.getPassword(),""); } }
|
定义shiro配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Configuration public class ShiroConfig {
@Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String,String> filterMap = new LinkedHashMap<>(); filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); filterMap.put("/logout", "logout"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); shiroFilterFactoryBean.setLoginUrl("/toLogin"); shiroFilterFactoryBean.setUnauthorizedUrl("/noauth"); return shiroFilterFactoryBean; }
@Bean("securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); return securityManager; }
@Bean public UserRealm userRealm(){ return new UserRealm(); }
@Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } }
|
前台首页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1> 首页 </h1>
<div shiro:notAuthenticated=""> <a th:href="@{/toLogin}">登录</a> </div>
<div shiro:user=""> <a th:href="@{/logout}">注销</a> </div>
<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>
</body> </html>
|

实现


