
springboot+shiro之应用
用户认证:通过配置Shiro,能够实现多种用户认证方式,如用户名密码认证、OAuth、OpenID Connect等。 权限控制:通过用户-角色、角色-权限的关系,实现细粒度的权限管理。 URL访问控制:基于用户角色和权限,过滤不允许访问的URL。 Session管理:支持多种Session存储方式,如Redis、Memcached等,可以存储用户的Session状态。
发布日期:2021-05-27 02:54:25
浏览次数:35
分类:精选文章
本文共 8683 字,大约阅读时间需要 28 分钟。
Shiro安全框架在Web项目中的应用
在Web项目日常开发中,轻量级安全框架Shiro是一个非常有用的工具,主要用于用户认证、权限控制以及URL访问管理等。通过合理配置,Shiro可以帮助开发者快速实现基于角色的访问控制(RBAC)、基于权限的访问控制(ABAC)以及其他自定义校验逻辑。
Shiro的核心应用场景
Shiro适用于以下场景:
Shiro在生产环境中的配置
pom.xml配置
在项目的基础依赖中加入Shiro相关的jar包:
net.sf.json-lib json-lib 2.4 jdk15 org.crazycake shiro-redis 3.2.3 org.apache.shiro shiro-spring 1.4.0 org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test
application.properties配置
在项目配置文件中,添加Redis和Shiro的相关配置:
spring.redis.database=0spring.redis.host=127.0.0.1spring.redis.port=6379spring.redis.password=
Shiro的主配置类
在ShiroConfig
中,配置Shiro的安全管理器、过滤器以及缓存策略:
import org.apache.shiro.codec ?>"> filters = new HashMap<>(); filters.put("user", new SecurityFormAuthenticationFilter()); filters.put("croles", new SecurityRoleAuthorizationFilter()); filters.put("cperms", new SecurityPermissionAuthorizationFilter()); filters.put("logout", new SecurityLogoutFilter()); shiroFilterFactoryBean.setFilters(filters); // 定义接入口滤器链 MapfilterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/getVerifyCode", "anon"); filterChainDefinitionMap.put("/getSid", "anon"); filterChainDefinitionMap.put("/index.html*", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/**", "user,authc"); // 获取所有的权限信息,并构建资源控制 List permissionInfoList = permissionService.getAllRolePermissionList(); if (!permissionInfoList.isEmpty()) { for (PermissionInfo permissionInfo : permissionInfoList) { String urlPrefix = permissionInfo.getUrl().startsWith("/") ? "" : "/"; String resourceUrl = "/" + permissionInfo.getUrl(); String rolesString = String.join(",", permissionInfo.getRoleList().stream() .map(SysRole::getName) .collect(Collectors.toList())); filterChainDefinitionMap.put(resourceUrl, "user,authc," + "cperms[" + permissionInfo.getPermission() + "]" + (rolesString.isEmpty() ? "" : ",croles[" + rolesString.substring(0, rolesString.length() - 1) + "]")); } } // 过滤器链优先级调整 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { return new DefaultWebSecurityManager(); } @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm realm = new MyShiroRealm(); realm.setCachingEnabled(true); realm.setAuthenticationCachingEnabled(true); realm.setAuthorizationCachingEnabled(true); realm.setCredentialsMatcher(hashedCredentialsMatcher()); return realm; } @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("md5"); matcher.setHashIterations(2); return matcher; } @Bean public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); redisCacheManager.setKeyPrefix(CACHE_KEY); redisCacheManager.setPrincipalIdFieldName("id"); redisCacheManager.setExpire(EXPIRE); return redisCacheManager; } @Bean public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setDatabase(redisProperties.getDatabase()); redisManager.setHost(redisProperties.getHost() + ":" + redisProperties.getPort()); return redisManager; } @Bean public SessionManager sessionManager() { return new ShiroSessionManager(); } // 其他Bean配置...}
SecurityLogoutFilter的实现
SecurityLogoutFilter
类用于用户退出系统时的处理逻辑:
public class SecurityLogoutFilter extends LogoutFilter { private static final Logger log = LoggerFactory.getLogger(SecurityLogoutFilter.class); @Value("${safe.switch}") private String safe; @Override protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; Subject subject = getSubject(request, response); if (currentUser == null) { log.info("用户未登录,无法退出系统"); } else { logout(subject); log.info("用户" + currentUser.getName() + "正常退出!"); } return false; } // 其他方法...}
登录处理
@RestControllerpublic class LoginController { @RequestMapping("/login") public Object login(HttpServletRequest request, HttpServletResponse response, @RequestBody Mapparams) { String username = params.get("username"); String pwd = params.get("password"); try { Subject subject = SecurityUtils.getSubject(); // 清除旧Session subject.logout(); UsernamePasswordToken token = new UsernamePasswordToken(username, pwd); subject.login(token); SysUser user = (SysUser) subject.getPrincipal(); // 返回用户信息和Token return ResponseData.ok(toJson(user)); } catch (Exception e) { // 处理异常,如用户名不存在或密码错误等 return ResponseData.fail("登录失败", 500); } }}
ShiroSessionManager的实现
public class ShiroSessionManager extends DefaultWebSessionManager { public ShiroSessionManager() { setDeleteInvalidSessions(true); } @Override public Serializable getSessionId(ServletRequest request, ServletResponse response) { String token = request.getHeader("Authorization"); if (!ObjectUtils.isEmpty(token)) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "Stateless request"); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return token; } else { return super.getSessionId(request, response); } }}
权限管理
public class MyShiroRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); SysUser user = (SysUser) principal.getPrimaryPrincipal(); Listroles = user.getRoles(); for (SysRole role : roles) { info.addRole(role.getName()); } List permissions = permissionService.getPermissionListByUserId(user.getId()); for (SysPermission permission : permissions) { info.addPermission(permission.getPermission()); } return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { String username = token.getPrincipal().toString(); SysUser user = userService.getUserByName(username); if (user == null) { throw new UnknownAccountException(); } else { SimpleAuthenticationInfo info = new SimpleAuthenticationInfo( user, user.getPassword(), ByteSourceUtils.bytes(user.getCredentialsSalt()) ); return info; } }}
总结
通过上述配置和实现,Shiro框架可以有效地对Web应用进行用户认证、权限控制和URL过滤。在实际项目中,可根据需求 进行相应的扩展和配置,提升应用的安全性和稳定性。