本节来使用SpringBoot+Mybatis+Mybatis Plus+Shiro实现简单的项目架构,主要实现的是使用Shiro进行登录验证和权限的验证,以下是实现的全过程,如果有不明白的地方可以下载代码示例:https://download.csdn.net/download/feritylamb/11490995
1、搭建一个SpringBoot项目,参考文章https://blog.csdn.net/feritylamb/article/details/98673201
2、在项目中集成Mybatis,参考文章https://blog.csdn.net/feritylamb/article/details/95771197
3、使用Mybatis Plus生成项目中使用的类,参考文章https://blog.csdn.net/feritylamb/article/details/97616980
4、完成以上几步以后就可以实现shiro的代码了,在pox.xml文件中添加项目所需要的依赖
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.gpsbd</groupId>
- <artifactId>hsgpsdw</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.7.RELEASE</version>
- </parent>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- </properties>
- <dependencies>
- <!-- springBoot依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!-- mysql依赖 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <scope>runtime</scope>
- </dependency>
- <!-- fastjson -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.15</version>
- </dependency>
- <!-- mybatisplus依赖 -->
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>2.2.0</version>
- </dependency>
- <!-- freemarker -->
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- </dependency>
- <!-- Shiro依赖 -->
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
- </project>
5、创建MyRealm文件实现登录验证和角色权限验证,代码如下
- package com.gpssoft.config.shiro;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Lazy;
- import com.gpssoft.model.Permissions;
- import com.gpssoft.model.vo.UserVo;
- import com.gpssoft.service.PermissionsService;
- import com.gpssoft.service.UsersService;
- public class MyRealm extends AuthorizingRealm {
- @Autowired
- private UsersService usersService;
- @Autowired
- private PermissionsService permissionsService;
- @Override
- public boolean supports(AuthenticationToken token) {
- return token instanceof MyToken;
- }
- /*
- * 只有当需要检测用户权限的时候才会调用此方法,例如checkRole,checkPermission之类的
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- // 根据用户名查找角色,请根据需求实现
- UserVo user = (UserVo) principals.getPrimaryPrincipal();
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- // 根据token获取用户的角色和权限
- String[] roleIds = user.getRoleIds().split(",");
- List<Permissions> permissions = new ArrayList<Permissions>();
- for (String roleId : roleIds) {
- permissions.addAll(permissionsService.getPermissionsByRoleId(Integer.parseInt(roleId)));
- }
- String[] roles = user.getRoleKeys().split(",");
- for (String role : roles) {
- authorizationInfo.addRole(role);
- }
- for (Permissions permis : permissions) {
- if (permis.getPermis() != null && !permis.getPermis().equals("")) {
- authorizationInfo.addStringPermission(permis.getPermis());
- }
- }
- return authorizationInfo;
- }
- /*
- * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
- String token = (String) auth.getCredentials();
- if (token == null) {
- throw new AuthenticationException("token invalid");
- }
- UserVo user = usersService.getUserByToken(token);
- if (user == null) {
- throw new AuthenticationException(); // 如果密码错误
- }
- // 然后进行客户端消息摘要和服务器端消息摘要的匹配
- return new SimpleAuthenticationInfo(user, token, getName());
- }
- }
6、创建ShiroConfig文件,代码如下
- package com.gpssoft.config.shiro;
- import java.util.HashMap;
- import java.util.Map;
- import javax.servlet.Filter;
- import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
- import org.apache.shiro.mgt.DefaultSubjectDAO;
- import org.apache.shiro.spring.LifecycleBeanPostProcessor;
- import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
- import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
- import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
- import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- @Configuration
- public class ShiroConfig {
- @Bean
- public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
- Map<String, Filter> filterMap = new HashMap<String, Filter>();
- filterMap.put("myfilter", new MyFilter());
- factoryBean.setFilters(filterMap);
- factoryBean.setSecurityManager(securityManager);
- Map<String, String> filterRuleMap = new HashMap<String, String>();
- // filterRuleMap.put("/users/getUser", "anon");
- // 过滤应用接口
- filterRuleMap.put("/**", "myfilter");
- factoryBean.setFilterChainDefinitionMap(filterRuleMap);
- return factoryBean;
- }
- @Bean(name = "securityManager")
- public DefaultWebSecurityManager securityManager() {
- DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
- manager.setRealm(myAuthRealm());
- return manager;
- }
- @Bean(name = "myRealm")
- public MyRealm myAuthRealm() {
- MyRealm myRealm = new MyRealm();
- return myRealm;
- }
- @Bean
- public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
- DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
- advisorAutoProxyCreator.setProxyTargetClass(true);
- return advisorAutoProxyCreator;
- }
- /**
- * 开启aop注解支持
- * @param securityManager
- * @return
- */
- @Bean
- public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
- AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
- authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
- return authorizationAttributeSourceAdvisor;
- }
- }
7、创建所需要的Filter文件类
- package com.gpssoft.config.shiro;
- import java.io.PrintWriter;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.apache.shiro.web.filter.AccessControlFilter;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.gpssoft.common.ErrorEnum;
- import com.gpssoft.model.Result;
- public class MyFilter extends AccessControlFilter {
- @Override
- protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)throws Exception {
- return false;
- }
- @Override
- protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
- HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- String authorization = httpServletRequest.getHeader("token");
- System.out.println("token验证"+authorization);
- if (authorization!=null) {
- try {
- MyToken token = new MyToken(authorization);
- // 提交给realm进行登入,如果错误他会抛出异常并被捕获
- getSubject(request, response).login(token);
- return true;
- } catch (Exception e) {
- response401(request, response);
- return false;
- }
- } else {
- response401(request, response);
- return false;
- }
- }
- private void response401(ServletRequest req, ServletResponse resp) throws Exception {
- //HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
- PrintWriter out = null;
- //JSONObject jsonObject = new JSONObject();
- Result result = new Result();
- result.setMsg(ErrorEnum.E_401.getErrorMsg());
- result.setCode(ErrorEnum.E_401.getErrorCode());
- resp.setCharacterEncoding("UTF-8");
- resp.setContentType("application/json");
- out = resp.getWriter();
- out.println(JSON.toJSON(result));
- }
- }
以下是Shiro权限管理的讲解:
一、概念
Shiro是一个安全框架,可以进行角色、权限管理。
Shiro主要功能如下:
Authentication(认证):用户身份识别,通常被称为用户“登录”
Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。
Session Management(会话管理):特定于用户的会话管理,甚至在非web 或 EJB 应用程序。
Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。
二、主要的类
1.Subject:当前用户,Subject可以是一个人,也可以是第三方服务
2.SecurityManager:管理所有Subject,可以配合内部安全组件。
3.principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。
4.credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。
最常见的principals和credentials组合就是用户名/密码了。
5.Realms:用于进行权限信息的验证,需要自己实现。
6.Realm 本质上是一个特定的安全 DAO:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。
在配置 Shiro 的时候,你必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)。
我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
7.SimpleHash,可以通过特定算法(比如md5)配合盐值salt,对密码进行多次加密。
三、Shiro配置
1.Spring集成Shiro一般通过xml配置,SpringBoot集成Shiro一般通过java代码配合@Configuration和@Bean配置。
2.Shiro的核心通过过滤器Filter实现。Shiro中的Filter是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。
3.SpringBoot集成Shiro,我们需要写的主要是两个类,ShiroConfiguration类,还有继承了AuthorizingRealm的Realm类
ShiroConfiguration类,用来配置Shiro,注入各种Bean。
包括过滤器(shiroFilter)、安全事务管理器(SecurityManager)、密码凭证(CredentialsMatcher)、aop注解支持(authorizationAttributeSourceAdvisor)等等
Realm类,包括登陆认证(doGetAuthenticationInfo)、授权认证(doGetAuthorizationInfo)
四、权限拦截 Filter
当运行一个Web应用程序时,Shiro将会创建一些有用的默认 Filter 实例,并自动地将它们置为可用,而这些默认的 Filter 实例是被 DefaultFilter 枚举类定义的,当然我们也可以自定义 Filter 实例
配置缩写 | 对应的过滤器 | 功能 |
---|---|---|
anon | AnonymousFilter | 指定url可以匿名访问 |
authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取username 、password ,rememberMe 等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 |
authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 |
logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 |
noSessionCreation | NoSessionCreationFilter | 禁止创建会话 |
perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 |
port | PortFilter | 需要指定端口才能访问 |
rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 |
roles | RolesAuthorizationFilter | 需要指定角色才能访问 |
ssl | SslFilter | 需要https请求才能访问 |
user | UserFilter | 需要已登录或“记住我”的用户才能访问 |
至此,这篇文章就结束了,欢迎大家交流学习。
代码示例:https://download.csdn.net/download/feritylamb/11490995