Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。相比较Spring Security,shiro有小巧、简单、易上手等的优点。所以很多框架都在使用shiro。
Shiro包含了三个核心组件:Subject, SecurityManager 和 Realms。
- Subject 代表了当前用户的安全操作。
- SecurityManager 则管理所有用户的安全操作。它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
- Realm 充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
下面通过示例来演示SpringBoot如何来整合Shiro
1、创建项目ShiroDemo
2、配置POM,添加SpringBoot以及Shiro依赖
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>0.2.23</version> </dependency> <!-- shiro权限控制框架 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> </dependencies>
3、编写MyShiroRealm类,实现AuthorizingRealm接口
public class MyShiroRealm extends AuthorizingRealm { /** * 授权用户权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //获取用户 User user = (User)SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获取用户角色 Set<String> roleSet = new HashSet<String>(); roleSet.add("100002"); info.setRoles(roleSet); //获取用户权限 Set<String> permissionSet = new HashSet<String>(); permissionSet.add("权限添加"); permissionSet.add("权限删除"); info.setStringPermissions(permissionSet); return info; } /** * 验证用户身份 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String username = token.getUsername(); String password = String.valueOf(token.getPassword()); Map<String, Object> map = new HashMap<String, Object>(); map.put("nickname", username); //密码进行加密处理 明文为 password+name String paw = password+username; String pawDES = MyDES.encryptBasedDes(paw); map.put("pswd", pawDES); User user = new User(); user.setId("112222"); user.setUsername(username); user.setPassword(pawDES); return new SimpleAuthenticationInfo(user, password, getName()); } }
4、实现ShiroConfiguration
@Configuration public class ShiroConfiguration { /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles * */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); //自定义拦截器 Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>(); //限制同一帐号同时在线的个数。 //filtersMap.put("kickout", kickoutSessionControlFilter()); shiroFilterFactoryBean.setFilters(filtersMap); // 权限控制map. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 配置不会被拦截的链接 顺序判断 // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了 // 从数据库获取动态的权限 // filterChainDefinitionMap.put("/add", "perms[权限添加]"); // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> //logout这个拦截器是shiro已经实现好了的。 // 从数据库获取 /*List<SysPermissionInit> list = sysPermissionInitService.selectAll(); for (SysPermissionInit sysPermissionInit : list) { filterChainDefinitionMap.put(sysPermissionInit.getUrl(), sysPermissionInit.getPermissionInit()); }*/ shiroFilterFactoryBean .setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(myShiroRealm()); // 自定义缓存实现 使用redis //securityManager.setCacheManager(cacheManager()); // 自定义session管理 使用redis //securityManager.setSessionManager(sessionManager()); //注入记住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } public MyShiroRealm myShiroRealm(){ return new MyShiroRealm(); } /** * cookie对象; * @return */ public SimpleCookie rememberMeCookie(){ //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //<!-- 记住我cookie生效时间30天 ,单位秒;--> simpleCookie.setMaxAge(2592000); return simpleCookie; } /** * cookie管理对象;记住我功能 * @return */ public CookieRememberMeManager rememberMeManager(){ CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位) cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } }
5、编写LoginController类测试Shiro
@RestController public class LoginController { @RequestMapping(value="/login",method=RequestMethod.POST) public String login(String username, String password,String vcode,Boolean rememberMe){ System.out.println(username); UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe); SecurityUtils.getSubject().login(token); return "loginSuccess"; } @RequestMapping(value="/index",method=RequestMethod.GET) public String home(){ Subject subject = SecurityUtils.getSubject(); User principal = (User)subject.getPrincipal(); return "Home"; } }
- 在postman中访问http://127.0.0.1:8080/login,Body中携带参数以及值
- 访问http://127.0.0.1:8080/index,从Subject中获取登录后的用户信息
来源:https://www.cnblogs.com/ncy1/p/9478865.html