springboot+shiro之应用
发布日期:2021-05-27 02:54:25 浏览次数:35 分类:精选文章

本文共 8683 字,大约阅读时间需要 28 分钟。

Shiro安全框架在Web项目中的应用

在Web项目日常开发中,轻量级安全框架Shiro是一个非常有用的工具,主要用于用户认证、权限控制以及URL访问管理等。通过合理配置,Shiro可以帮助开发者快速实现基于角色的访问控制(RBAC)、基于权限的访问控制(ABAC)以及其他自定义校验逻辑。

Shiro的核心应用场景

Shiro适用于以下场景:

  • 用户认证:通过配置Shiro,能够实现多种用户认证方式,如用户名密码认证、OAuth、OpenID Connect等。
  • 权限控制:通过用户-角色、角色-权限的关系,实现细粒度的权限管理。
  • URL访问控制:基于用户角色和权限,过滤不允许访问的URL。
  • Session管理:支持多种Session存储方式,如Redis、Memcached等,可以存储用户的Session状态。
  • 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); // 定义接入口滤器链 Map
    filterChainDefinitionMap = 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 Map
    params) { 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();                List
    roles = 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过滤。在实际项目中,可根据需求 进行相应的扩展和配置,提升应用的安全性和稳定性。

    上一篇:Java之死循环中new对象出现OOM问题
    下一篇:Java之proto初尝试

    发表评论

    最新留言

    留言是一种美德,欢迎回访!
    [***.207.175.100]2025年05月01日 05时30分46秒